Этот коммит содержится в:
2019-11-05 01:14:53 +03:00
Коммит 499374305a
29 изменённых файлов: 1004 добавлений и 0 удалений

87
src/App.php Обычный файл
Просмотреть файл

@@ -0,0 +1,87 @@
<?php
use MyApp\Core\Config;
use MyApp\Core\Router;
class App
{
private $prefix = 'MyApp\\';
private $classDirs = [
'Controller\\' => 'controllers/',
'Core\\' => 'core/',
'Model\\' => 'models/',
'View\\' => 'views/',
];
private $basedir = __DIR__;
/**
* @var Config
*/
public $config;
public function __construct()
{
global $app;
$app = $this;
spl_autoload_register([$this, 'autoload']);
$this->config = (new Config())->setDbName('db')
->setDbPort(3306)
->setDbUser('user')
->setDbPassword('password')
->setSrcDir($this->basedir)
->setTimezone('Europe/Moscow')
->setClassDirs($this->classDirs)
->setControllersDir($this->basedir.'/controllers/')
->setControllersNamespace('\\MyApp\\Controller\\')
->setSiteName('BadPing. Nagios better');
new Router();
}
/**
* Autoload function.
*
* @param string $className
*/
public function autoload(string $className)
{
if (0 !== strpos($className, $this->prefix)) {
return;
}
$fileName = substr($className, strlen($this->prefix));
$fileName = str_replace(array_keys($this->classDirs), array_values($this->classDirs), $fileName);
$fileName = $this->basedir.'/'.str_replace('\\', '/', $fileName).'.php';
if (file_exists($fileName)) {
require $fileName;
}
}
/**
* Parse tags from method comments.
*
* @param string $comment
* @param string $tags
*
* @return array|null
*/
public function parseTagsFromComment(string $comment, string $tags = 'RouteRegExp|HttpMethod')
{
if (preg_match_all("/^\\ *\\* \\@(?<type>$tags)\\ =\\ \"(?<value>.*)\\\".*\$/m", $comment, $matches)) {
$out = [];
foreach ($matches['type'] as $key => $type) {
if ('HttpMethod' == $type) {
$out[$type] = explode(',', $matches['value'][$key]);
} else {
$out[$type] = $matches['value'][$key];
}
}
return $out;
}
return null;
}
}

17
src/controllers/DefaultController.php Обычный файл
Просмотреть файл

@@ -0,0 +1,17 @@
<?php
namespace MyApp\Controller;
use MyApp\Core\Controller;
use MyApp\View\DefaultView as View;
class DefaultController extends Controller
{
/**
* @RouteRegExp = "|^/$|"
*/
public function index()
{
(new View())->index();
}
}

19
src/controllers/ErrorsController.php Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
<?php
namespace MyApp\Controller;
use MyApp\Core\Controller;
class ErrorsController extends Controller
{
public function get404()
{
http_response_code(404);
echo 404;
}
public function post404()
{
echo 404;
}
}

235
src/core/Config.php Обычный файл
Просмотреть файл

@@ -0,0 +1,235 @@
<?php
namespace MyApp\Core;
class Config
{
/**
* @var string
*/
private $dbName;
/**
* @var int
*/
private $dbPort;
/**
* @var string
*/
private $dbUser;
/**
* @var string
*/
private $dbPassword;
/**
* @var array
*/
private $classDirs;
/**
* @var string
*/
private $srcDir;
/**
* @var string
*/
private $controllersDir;
/**
* @var string
*/
private $controllersNamespace;
/**
* @var string
*/
private $siteName;
/**
* @return string
*/
public function getDbName(): string
{
return $this->dbName;
}
/**
* @param string $dbName
*
* @return Config
*/
public function setDbName(string $dbName)
{
$this->dbName = $dbName;
return $this;
}
/**
* @return int
*/
public function getDbPort(): int
{
return $this->dbPort;
}
/**
* @param int $dbPort
*
* @return Config
*/
public function setDbPort(int $dbPort)
{
$this->dbPort = $dbPort;
return $this;
}
/**
* @return string
*/
public function getDbUser(): string
{
return $this->dbUser;
}
/**
* @param string $dbUser
*
* @return Config
*/
public function setDbUser(string $dbUser)
{
$this->dbUser = $dbUser;
return $this;
}
/**
* @return string
*/
public function getDbPassword(): string
{
return $this->dbPassword;
}
/**
* @param string $dbPassword
*
* @return Config
*/
public function setDbPassword(string $dbPassword)
{
$this->dbPassword = $dbPassword;
return $this;
}
/**
* @param string $timezone
*
* @return $this
*/
public function setTimezone(string $timezone)
{
date_default_timezone_set($timezone);
return $this;
}
/**
* @return array
*/
public function getClassDirs(): array
{
return $this->classDirs;
}
/**
* @param array $classDirs
*
* @return Config
*/
public function setClassDirs(array $classDirs)
{
$this->classDirs = $classDirs;
return $this;
}
/**
* @return string
*/
public function getSrcDir(): string
{
return $this->srcDir;
}
/**
* @param string $srcDir
*
* @return Config
*/
public function setSrcDir(string $srcDir)
{
$this->srcDir = $srcDir;
return $this;
}
/**
* @return string
*/
public function getControllersDir(): string
{
return $this->controllersDir;
}
/**
* @param string $controllersDir
*
* @return Config
*/
public function setControllersDir(string $controllersDir)
{
$this->controllersDir = $controllersDir;
return $this;
}
/**
* @return string
*/
public function getControllersNamespace(): string
{
return $this->controllersNamespace;
}
/**
* @param string $controllersNamespace
*
* @return Config
*/
public function setControllersNamespace(string $controllersNamespace)
{
$this->controllersNamespace = $controllersNamespace;
return $this;
}
/**
* @return string
*/
public function getSiteName(): string
{
return $this->siteName;
}
/**
* @param string $siteName
*
* @return Config
*/
public function setSiteName(string $siteName)
{
$this->siteName = $siteName;
return $this;
}
}

7
src/core/Controller.php Обычный файл
Просмотреть файл

@@ -0,0 +1,7 @@
<?php
namespace MyApp\Core;
class Controller
{
}

7
src/core/Model.php Обычный файл
Просмотреть файл

@@ -0,0 +1,7 @@
<?php
namespace MyApp\Core;
class Model
{
}

103
src/core/Router.php Обычный файл
Просмотреть файл

@@ -0,0 +1,103 @@
<?php
namespace MyApp\Core;
use ReflectionMethod;
/**
* Class Router.
*/
class Router
{
/**
* @var array
*/
private $routes = [];
public function __construct()
{
$this->getRoutesFromControllers();
$this->addRoute('/^.*$/', 'MyApp\\Controller\\ErrorsController', 'get404', ['GET']);
$this->addRoute('/^.*$/', 'MyApp\\Controller\\ErrorsController', 'post404', ['POST', 'PUT', 'DELETE']);
$this->run();
}
/**
* Get Routes from a comment on method in Controllers.
*/
private function getRoutesFromControllers()
{
/* @var \App $app */
global $app;
/* @var Config $config */
$config = $app->config;
$controllersDir = $config->getControllersDir();
$controllersNamespace = $config->getControllersNamespace();
$files = scandir($controllersDir);
foreach ($files as $file) {
$className = strstr($file, '.php', true);
$fileName = $controllersDir.$file;
if (is_file($fileName) && false !== $className) {
try {
$refClass = new \ReflectionClass($controllersNamespace.$className);
$methods = $refClass->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) {
$tags = $app->parseTagsFromComment($method->getDocComment());
if (is_array($tags)) {
if (array_key_exists('RouteRegExp', $tags)) {
if (!array_key_exists('HttpMethod', $tags)) {
$tags['HttpMethod'] = ['GET'];
}
$this->addRoute($tags['RouteRegExp'], $method->class, $method->name, $tags['HttpMethod']);
}
}
}
} catch (\ReflectionException $e) {
var_dump($e);
}
}
}
}
/**
* Add route to array.
*
* @param string $regExp
* @param string $className
* @param string $classMethod
* @param array $httpMethods
*/
private function addRoute(string $regExp, string $className, string $classMethod, array $httpMethods)
{
foreach ($httpMethods as $httpMethod) {
$this->routes[strtoupper($httpMethod)][] = [$regExp, $className, $classMethod];
}
}
/**
* Run parse request.
*/
private function run()
{
if (array_key_exists($_SERVER['REQUEST_METHOD'], $this->routes)) {
foreach ($this->routes[$_SERVER['REQUEST_METHOD']] as $route_array) {
if (preg_match($route_array[0], $_SERVER['REQUEST_URI'], $matches)) {
$obj = new $route_array[1]();
$param_arr = [];
foreach ($matches as $key => $value) {
if (!is_int($key)) {
$param_arr[] = $value;
}
}
call_user_func_array([$obj, $route_array[2]], $param_arr);
break;
}
}
}
}
}

44
src/core/View.php Обычный файл
Просмотреть файл

@@ -0,0 +1,44 @@
<?php
namespace MyApp\Core;
class View
{
/**
* @var string
*/
public $title = '';
public function json($data)
{
}
public function render($template)
{
/* @var \App $app */
global $app;
$fileName = $app->config->getSrcDir().'/templates/'.$template.'.tpl.php';
if (file_exists($fileName)) {
ob_start();
require $fileName;
ob_end_flush();
}
}
/**
* @param string $title
*
* @return View
*/
public function setTitle(string $title)
{
/* @var \App $app */
global $app;
$this->title = $title.' &mdash; '.$app->config->getSiteName();
return $this;
}
}

3
src/templates/default/index.tpl.php Обычный файл
Просмотреть файл

@@ -0,0 +1,3 @@
<?php
require __DIR__.'/../shared/head.php';

18
src/templates/shared/head.php Обычный файл
Просмотреть файл

@@ -0,0 +1,18 @@
<!doctype html>
<html lang="ru-RU">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/img/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/img/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/img/favicon/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/assets/img/favicon/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="/assets/css/normalize.css">
<link rel="stylesheet" href="/assets/css/style.css">
<title><?= $this->title; ?></title>
</head>

13
src/views/DefaultView.php Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
<?php
namespace MyApp\View;
use MyApp\Core\View;
class DefaultView extends View
{
public function index()
{
$this->setTitle('Index')->render('default/index');
}
}