From 499374305ad44f7d5f5e974ef9bffa7719d040b2 Mon Sep 17 00:00:00 2001 From: Igor V Belousov Date: Tue, 5 Nov 2019 01:14:53 +0300 Subject: [PATCH] first commit --- .gitignore | 2 + docker-compose.yml | 37 ++ docker/nginx.docker | 5 + docker/nginx_default.conf | 18 + docker/php-fpm.docker | 7 + public/assets/css/normalize.css | 349 ++++++++++++++++++ public/assets/css/style.css | 0 .../img/favicon/android-chrome-192x192.png | Bin 0 -> 2863 bytes .../img/favicon/android-chrome-384x384.png | Bin 0 -> 5959 bytes .../assets/img/favicon/apple-touch-icon.png | Bin 0 -> 2825 bytes public/assets/img/favicon/favicon-16x16.png | Bin 0 -> 602 bytes public/assets/img/favicon/favicon-32x32.png | Bin 0 -> 851 bytes public/assets/img/favicon/mstile-150x150.png | Bin 0 -> 1784 bytes .../assets/img/favicon/safari-pinned-tab.svg | 1 + public/browserconfig.xml | 9 + public/favicon.ico | Bin 0 -> 15086 bytes public/index.php | 4 + public/site.webmanifest | 19 + src/App.php | 87 +++++ src/controllers/DefaultController.php | 17 + src/controllers/ErrorsController.php | 19 + src/core/Config.php | 235 ++++++++++++ src/core/Controller.php | 7 + src/core/Model.php | 7 + src/core/Router.php | 103 ++++++ src/core/View.php | 44 +++ src/templates/default/index.tpl.php | 3 + src/templates/shared/head.php | 18 + src/views/DefaultView.php | 13 + 29 files changed, 1004 insertions(+) create mode 100644 .gitignore create mode 100644 docker-compose.yml create mode 100644 docker/nginx.docker create mode 100644 docker/nginx_default.conf create mode 100644 docker/php-fpm.docker create mode 100644 public/assets/css/normalize.css create mode 100644 public/assets/css/style.css create mode 100644 public/assets/img/favicon/android-chrome-192x192.png create mode 100644 public/assets/img/favicon/android-chrome-384x384.png create mode 100644 public/assets/img/favicon/apple-touch-icon.png create mode 100644 public/assets/img/favicon/favicon-16x16.png create mode 100644 public/assets/img/favicon/favicon-32x32.png create mode 100644 public/assets/img/favicon/mstile-150x150.png create mode 100644 public/assets/img/favicon/safari-pinned-tab.svg create mode 100644 public/browserconfig.xml create mode 100644 public/favicon.ico create mode 100644 public/index.php create mode 100644 public/site.webmanifest create mode 100644 src/App.php create mode 100644 src/controllers/DefaultController.php create mode 100644 src/controllers/ErrorsController.php create mode 100644 src/core/Config.php create mode 100644 src/core/Controller.php create mode 100644 src/core/Model.php create mode 100644 src/core/Router.php create mode 100644 src/core/View.php create mode 100644 src/templates/default/index.tpl.php create mode 100644 src/templates/shared/head.php create mode 100644 src/views/DefaultView.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f123e24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/* +.php_cs.cache \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9200437 --- /dev/null +++ b/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: diff --git a/docker/nginx.docker b/docker/nginx.docker new file mode 100644 index 0000000..75e4434 --- /dev/null +++ b/docker/nginx.docker @@ -0,0 +1,5 @@ +FROM nginx:alpine + +COPY ./nginx_default.conf /etc/nginx/conf.d/default.conf + +WORKDIR /app \ No newline at end of file diff --git a/docker/nginx_default.conf b/docker/nginx_default.conf new file mode 100644 index 0000000..4da4035 --- /dev/null +++ b/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; + } +} \ No newline at end of file diff --git a/docker/php-fpm.docker b/docker/php-fpm.docker new file mode 100644 index 0000000..2af8053 --- /dev/null +++ b/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 diff --git a/public/assets/css/normalize.css b/public/assets/css/normalize.css new file mode 100644 index 0000000..192eb9c --- /dev/null +++ b/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; +} diff --git a/public/assets/css/style.css b/public/assets/css/style.css new file mode 100644 index 0000000..e69de29 diff --git a/public/assets/img/favicon/android-chrome-192x192.png b/public/assets/img/favicon/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..412923170cc7ef5f9bef3f5191db7a9cf85252e2 GIT binary patch literal 2863 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 literal 0 HcmV?d00001 diff --git a/public/assets/img/favicon/favicon-16x16.png b/public/assets/img/favicon/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..f256416fd860610aa8dd2074249d60ceabddc0f7 GIT binary patch literal 602 zcmV-g0;TPx#%uq~JMNDaN0000FJZ6ZAh!`$J5D*X~Mr8m10463S z6c`&9H(?)5cPUkWAy0W5N^}GS1RozCO-)R7b8`R#A`CWR1T$R=DN6wX0Te=QB`7KZ z0RbEw91%ck0002~{{H9a=>|1m_xbvzqoT93vs6-2U3ZSf#l@ACmA1au*xcmK&eHAg z@9FFN^fxx1r0&en_~D|fMnTqQfS9JW#C?;fBusHcWrV%Gy?}s#mzS6A=H^Qr9Q@PM zRbc09GBWFQg!jhGb9?RXPf!1ol7_xFi~s-t9&}PpQvf3P{RNU1JoJ+=SwMNDd#2a< zJmHh{sL=Fd^xH`f>6c9a005s!L_t&-(`C=c5`r)Q1W>9dD9zqN5{mR<@Ad!xNtjF+ zM)&w;_pl7}AEnoA2~8M6ZlRV~L&tS@5ONb$kx5bXkmYap9E1azz`^D%fP&3>)F+dZ zX=4Ncu%;4$m4lsg1??L6%lnzd6hv%C_vBHe0R<1BJjsifPbbGPx_;tYMknk{H%uI+ zh(ei`r0E8a=ThU5z%I2h`}4cH@&!4k5Ag;!KJWkl09SfcSaechcOY6Cgx@G{a;ABePT> o%h=S&#LUDT#0SfONT5nC0O}VJbn-$ql>h($07*qoM6N<$f~iyX`2YX_ literal 0 HcmV?d00001 diff --git a/public/assets/img/favicon/favicon-32x32.png b/public/assets/img/favicon/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..c5e0dd66b65ec0e8046e7e81ec234ddd4607af8a GIT binary patch literal 851 zcmV-Z1FZasP)Px$4p2-~MNDaNA5C{4Omq$%D;YFQ2smOVR(}8h0RR91 z009C489o3204!O98%S~h001aee=1jjELnppR)8i`eEA11pzHt!otEhMdU+7 zMDp|c4-XG*ZEgFSoK8+o;^h05o1e(b&7-5Fm7DPD>+DGc1Rx+F)799@&G-Gawfe`( zyuH1gth+v7fOU1bq zSpgRX=?IA36pdZe%lkh`7K}5IcIAJ&-<<#K&TJxaoaFPV*z*jAot~X!qESB0rR%th zl2M?F;-bro^RPBD_g?23jUB=e^0$$M{qT5ySFd`8+qGp50AB%s>5ks;^nMVI75xAO zI+pp2du?3q`VhdO=s*v7ZJZxCLxX0m-5davm(go3`ybRq)#Npv0sAm4?E`eJ0u2qu z02@GAjsvQ(UB&`KR_XRypGWTiyKGw!*0A-|gh61bXi2#(=(@gIOnVhS;GsD4z-A+S zNoYm@cuzF^7KER{O6p1DZ~*#(K2W5^wAJ$idk^|Rk)&2LutP_)yXc+gp92IYforC+ z)D5A^T5ZNa04L)Ba1B|wEfF1KD>_Ou47f>>g>s2lewY>$4m?z(%7n^lW+wu;ZCCC} zbTs%|iAo;nU;hFtvO?%b|0}it0038dR9JLUVRs;Ka&Km7Y-J#Hd2nSQX>fF7004NL z`#0MO7XMo9QjZvqQA+BOKH@Q2YCYR@i8SI7M2dKB1|iiVBwo{$DspU^C@qtw zj1n;=4Qs;;gXk_MH5$~bw5ceSHmE8qZ9FIQ2khK)?z#7KKlj|v=cij5j7I8e9n%5; zKo{lfg8=|F&>yL(u9^g;9r<2W4kdX7dI3ONnf5OJunMbXVvycI%ZRyL1*(Dru!sO6 z={PFW#1UnOE7UQy0RRmZ^G$TImV1J(#aUHv8(yGc6?kxPpz8l}HcFvT?C$KSfZFL$ zHJy2V1G7)-pI*L_I60kzhEjpU5-yjUot>?OK-je_-F^Kq7_5*c-4sxU7gtEo9qV;m@1W?E*XOk1@?o7wE7nI z_bhMHAI9h3`!4_-E<*WuVRK%7sJWI|?`w1kZU7m1ta+=zXYvvL_9@R<hV&}vBaorAvZ~<-Og}BC%e(ve+{%ABb z@6dYne=FAd{Dk?k>u02|p7us}8gSwIJCQ|gb^eGo=m} zl+w393<%pOCOzj{ud*=Z+=O|hkPn%rE-IC6B&<|2M{fd2KO;F=i~&E?T(Y?p0^>^0 zSP)&a5#rovzv@41aP%bC%y@juA4(}Pcv0EzLXUxvqR&+Cn)qdWAD*5q7X~MJJF#bT!unT-yqt2yo-2yZbasn^DEyercJ(Mku^n#o zZr4y!s>%L8n)*rnHanPa(oG2TIBH)9E@0vd2Q7DF%gj7V-lVe#`Qg;~w5rg$0rX~< z8BxfEmtQ#^_Cp`k{v`7HVc(CWebXs#tFA9cG-8#Wz7zQ*RCoruFOi=;s74JTnudvTc;3V z=;#-CW9IS$;Q@)=x{N3SQ7<%9oFm4nYp|!OC9dG9g&PV2A;Z-eEl+Q{Qjd;{*#0HU_!FdnbDynN|6TmuQc+Z;@G2u zp&K2`>A}b?l&GC`0xOE8?b}QY(nlbt|8wkmRu(Fj!kmrP6%6fny2%b&0NAP*Oq_H}dHXpQE z)iGo-{1eDE37Jt05?@^WG}8h)`rxFvar7>aeBRb#@pbAdnSvcPIWzM9EUhY%Mz~)! zEFO71`#cvr64@>r`&K^o5gNGv)gumO112EraKwwLg6bcw$=G*pb|uBUt?B7HL!6Bl z(r7s|dK}Gt9vw8^$V6IsJQGw146S06GwWx5^m71~kLr^*y#H4DhYu72?bG7@kHX&pc}F|k literal 0 HcmV?d00001 diff --git a/public/assets/img/favicon/safari-pinned-tab.svg b/public/assets/img/favicon/safari-pinned-tab.svg new file mode 100644 index 0000000..6f2b2ec --- /dev/null +++ b/public/assets/img/favicon/safari-pinned-tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 0000000..b798281 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..da7efaf3dff7b6ec8d5ae305b8cb826edafbd572 GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..e4e33cf --- /dev/null +++ b/public/index.php @@ -0,0 +1,4 @@ + '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("/^\\ *\\* \\@(?$tags)\\ =\\ \"(?.*)\\\".*\$/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; + } +} diff --git a/src/controllers/DefaultController.php b/src/controllers/DefaultController.php new file mode 100644 index 0000000..b8522bf --- /dev/null +++ b/src/controllers/DefaultController.php @@ -0,0 +1,17 @@ +index(); + } +} diff --git a/src/controllers/ErrorsController.php b/src/controllers/ErrorsController.php new file mode 100644 index 0000000..81310fc --- /dev/null +++ b/src/controllers/ErrorsController.php @@ -0,0 +1,19 @@ +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; + } +} diff --git a/src/core/Controller.php b/src/core/Controller.php new file mode 100644 index 0000000..eabeab2 --- /dev/null +++ b/src/core/Controller.php @@ -0,0 +1,7 @@ +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; + } + } + } + } +} diff --git a/src/core/View.php b/src/core/View.php new file mode 100644 index 0000000..5e8a24e --- /dev/null +++ b/src/core/View.php @@ -0,0 +1,44 @@ +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; + } +} diff --git a/src/templates/default/index.tpl.php b/src/templates/default/index.tpl.php new file mode 100644 index 0000000..06e597c --- /dev/null +++ b/src/templates/default/index.tpl.php @@ -0,0 +1,3 @@ + + + + + + + + + + + + + + + + <?= $this->title; ?> + diff --git a/src/views/DefaultView.php b/src/views/DefaultView.php new file mode 100644 index 0000000..6929ac8 --- /dev/null +++ b/src/views/DefaultView.php @@ -0,0 +1,13 @@ +setTitle('Index')->render('default/index'); + } +}