first commit
2
.gitignore
поставляемый
Обычный файл
@ -0,0 +1,2 @@
|
|||||||
|
.idea/*
|
||||||
|
.php_cs.cache
|
37
docker-compose.yml
Обычный файл
@ -0,0 +1,37 @@
|
|||||||
|
version: '3.3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:latest
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- database:/var/lib/mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: 'db'
|
||||||
|
MYSQL_USER: 'user'
|
||||||
|
MYSQL_PASSWORD: 'password'
|
||||||
|
MYSQL_ROOT_PASSWORD: 'rootPassword'
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: ./docker
|
||||||
|
dockerfile: php-fpm.docker
|
||||||
|
volumes:
|
||||||
|
- "./public/:/app/public"
|
||||||
|
- "./src/:/app/src"
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
nginx:
|
||||||
|
build:
|
||||||
|
context: ./docker
|
||||||
|
dockerfile: nginx.docker
|
||||||
|
volumes:
|
||||||
|
- "./public/:/app/public"
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
volumes:
|
||||||
|
database:
|
5
docker/nginx.docker
Обычный файл
@ -0,0 +1,5 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY ./nginx_default.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
WORKDIR /app
|
18
docker/nginx_default.conf
Обычный файл
@ -0,0 +1,18 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
index index.php;
|
||||||
|
root /app/public;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri /index.php?$args;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass app:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
}
|
||||||
|
}
|
7
docker/php-fpm.docker
Обычный файл
@ -0,0 +1,7 @@
|
|||||||
|
FROM php:fpm-alpine
|
||||||
|
|
||||||
|
RUN set -ex \
|
||||||
|
&& apk --no-cache add postgresql-dev libpq freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev libzip zlib-dev libzip-dev \
|
||||||
|
&& docker-php-ext-install pdo pdo_mysql gd zip
|
||||||
|
|
||||||
|
WORKDIR /app
|
349
public/assets/css/normalize.css
поставляемый
Обычный файл
@ -0,0 +1,349 @@
|
|||||||
|
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the `main` element consistently in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background on active links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers.
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10.
|
||||||
|
* 2. Remove the padding in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
0
public/assets/css/style.css
Обычный файл
Двоичные данные
public/assets/img/favicon/android-chrome-192x192.png
Обычный файл
После Ширина: | Высота: | Размер: 2.8 KiB |
Двоичные данные
public/assets/img/favicon/android-chrome-384x384.png
Обычный файл
После Ширина: | Высота: | Размер: 5.8 KiB |
Двоичные данные
public/assets/img/favicon/apple-touch-icon.png
Обычный файл
После Ширина: | Высота: | Размер: 2.8 KiB |
Двоичные данные
public/assets/img/favicon/favicon-16x16.png
Обычный файл
После Ширина: | Высота: | Размер: 602 B |
Двоичные данные
public/assets/img/favicon/favicon-32x32.png
Обычный файл
После Ширина: | Высота: | Размер: 851 B |
Двоичные данные
public/assets/img/favicon/mstile-150x150.png
Обычный файл
После Ширина: | Высота: | Размер: 1.7 KiB |
1
public/assets/img/favicon/safari-pinned-tab.svg
Обычный файл
@ -0,0 +1 @@
|
|||||||
|
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="574.667" height="574.667" viewBox="0 0 431.000000 431.000000"><path d="M70.2 40.3L65 45.6l.2 139.9.3 139.9 5 1.4c2.8.7 7.3 2 10 2.7 5.4 1.6 48.1 13 84.5 22.6 12.4 3.3 24.8 6.6 27.5 7.4 2.8.8 16 4.4 29.5 8 13.5 3.6 46.3 12.4 72.9 19.5 26.7 7.2 48.8 13 49.3 13 .4 0 3-2.3 5.8-5.1l5-5V250c0-132.3-.1-139.9-1.7-140.4-1.6-.5-27-7.3-96.3-25.7-12.4-3.3-40-10.8-61.5-16.5-21.4-5.8-44.2-11.9-50.5-13.6-15.9-4.2-66-17.7-68-18.3-1-.3-3.5 1.4-6.8 4.8z"/></svg>
|
После Ширина: | Высота: | Размер: 507 B |
9
public/browserconfig.xml
Обычный файл
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="/assets/favicon/mstile-150x150.png"/>
|
||||||
|
<TileColor>#da532c</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
Двоичные данные
public/favicon.ico
Обычный файл
После Ширина: | Высота: | Размер: 15 KiB |
4
public/index.php
Обычный файл
@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
include dirname(__DIR__) . '/src/App.php';
|
||||||
|
|
||||||
|
new App();
|
19
public/site.webmanifest
Обычный файл
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"short_name": "",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/assets/favicon/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/assets/favicon/android-chrome-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
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.' — '.$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');
|
||||||
|
}
|
||||||
|
}
|