Схема работы сайта
Запос пользователя в адресной строке поступает в Front Controller где он обрабатывается с помощью роутера (маршрутизатора) в соответсвии с нашими маршрутами (роутами) прописанными в отдельном файле. Здесь же определяется какой контроллер и какой его метод (экшен) будет обрабатывать данный запрос. Уже назначенный контролер будет взаимодействовать с БД (базой данных) для получения необходимой информации и вызывать соответствующий файл представления (вид) для передачи пользователю запрашиваемой информации.
Для того, чтобы понять как это работает, лучше всего представить все в виде такой схемы:
Создаем файловую структуру сайта:
Папки:
- controller
- config
- components
- model
- views
Файлы:
- index.php
- .htaccess
Сразу приведу файл .htaccess полностью. Его нужно создать раньше, если вы работаете на OpenServer
DirectoryIndex index.php AddDefaultCharset utf-8 RewriteEngine on RewriteBase / RewriteRUle ^(.*)$ index.php
index.php
<?php // FRONT COTROLLER // 1. Общие настройки ini_set('display_errors', 1); error_reporting(E_ALL); // 2. Подключение файлов системы define('ROOT', dirname(__FILE__)); require_once(ROOT.'/components/Router.php'); // 3. Установка соединения с БД // 4. Вызов Router $router = new Router(); $router->run();
В общих настройках мы задали отображение ошибок. Это нужно нам. но не посетителям, поэтому при завершении работ с сайтом, отладке и размещении на хосте, эти строки нам нужно будет изменить. Эта информация может испугать законопослушных и неопытных посетителей сайта, или может быть использована злоумышленниками для взлома сайта.
Для подключения мы используем полный путь на диске, который мы получаем с помощью функции dirname()
и псевдо константы __FILE__
.
Для проверки содержимого константы ROOT(полный путь от корня файловой системы), мы можем вывести переменную ROOT следующим образом:
еcho ROOT;
Сразу после строк создания константы ROOT и подключения файла Router.php -
define('ROOT', dirname(__FILE__)); require_once(ROOT . '/components/Router.php'); еcho ROOT;
Соединения с БД на этом этапе мы выполнять не будем и вернемся к нему позже.
Вызов роутера можно добавить сейчас или сразу после описания нашего ротера я следующем шаге. Он будет заключаться в создании экземпляра класса Роутер - $router = new Router()
и запуске метода run() - $router->run();
;
Коль скоро мы подключили файл Router.php, то нам остается его создать в папке components
B нем пропишем следующий строки :<?php class Router { private $routes;//создаем массив в кот. хранятся наши маршруты public function __constructor(){ } public function run() { echo "It is file Roter.php";//Это для проверки подключения файла } }
Теперь, если мы откроем наш сайт, то увидим строки - It is file Roter.php -. Это говорит о том. что все подключено и правильно работает
Таким образом мы запустили наш Router и передали ему управление
Router
Первое с чего нам следует начать - маршруты (роуты). Они будут храниться в отдельном файле. Это очень удобно.
В папке config создадим для этого файл routes.php
Здесь мы и разместим наши роуты в виде массива:
routes.php
<?php return array( 'news' => 'news/index', // actionIndex in NewsController 'products' => 'product/list', // actionList in ProductController );
Роуты представляют собой пару в массиве.Запрос (то что пользователь набирает в адресной строке браузера) - Например: 'news'
и строка - 'news/index'
, которая содержит имя контроллера news
(первая часть), и имя экшена index
(функции обработчика запроса) - вторая часть.
Этот код - 'news' => 'news/index'
показывает, что будет вызван метод - actionIndex
в контроллере - NewsController
Здесь мы сами решаем, какой метод и какой контроллер будет обрабатывать наш запрос. Делаем это мы на этапе разработки нашего сайта.
Теперь наша задача заставить наш Router прочитать маршруты и помнить их на время выполнения кода.
Специально для этого мы создали переменную private $routes;
и конструктор public function __construct()
, в котором мы прочитаем и запомним роуты.
В конструкторе пишем две строки:
$routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath);
В первой - $routesPath = ROOT.'/config/routes.php';
мы указываем путь к роутам. Она состоит из пути к базовой директории ROOT и пути к созданному файлу.
Во второй строке мы присваиваем свойству routes -$this->routes
массив, который хранится в файле routes.php
Теперь в наше свойство попадет нужный нам массив.
Для того чтобы проверить все ли у нас подключилось и правильно работает мы в методе run() сделаем распечатку массива :
print_r($this->routes);
Получим такое сообщение на сайте :
Array ( [news] => news/index [products] => product/list ) It is file Router.php
Все конечные версии вы можете посмотреть на Гугл Диске
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } public function run() { print_r($this->routes); echo "It is file Router.php"; } }ЗАДАЧА 3
Теперь нам нужно реализовать метод run(). Это та часть, которая отвечает за анализ запроса и передачу управления
- Получение запроса
- Проверить наличие такого запроса в файле routes.php
- Если найдется совпадение. то определить какой контроллер и экшен будут обрабатывать это запрос
- Подключить файл, который содержит класс-контроллер
- Создать объект этого класса контроллер и вызвать нужный метод
Теперь по порядку:
Получение запроса
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } public function run() { if (!empty($_SERVER['REQUEST_URI'])) { $uri = trim($_SERVER['REQUEST_URI'], '/'); } echo $uri; } }
Здесь мы из супер глобального массива $_SERVER
по ключу 'REQUEST_URI'
получаем нужную строке запроса
Теперь идем на наш сайт и в строке запроса дописываем /news/ - например. Или любое другое значение. Нажимаем Enter и видим значение из строки на нашем сайте.
Теперь, для того, чтобы сделать наш код понятнее и красивее, мы можем вынести этот код в отдельный метод - private function getURI()
,а вызов сделаем из функции run() таким образом - $uri = $this->getURI();
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } //Returns request string private function getURI() { if (!empty($_SERVER['REQUEST_URI'])) { return trim($_SERVER['REQUEST_URI'], '/'); } } public function run() { $uri = $this->getURI(); echo $uri; } }
Метод getURI() мы сделали приватным, тем самым применили инкапсуляцию, потому как обращаться к этому методу мы планируем только из класса Роутер
Еще раз проверяем. Должно все работать точно так же как и в прошлый раз.
Проверить наличие такого запроса в файле routes.php
Теперь нам нужно найти такую строку запроса, которая содержится в переменной - $uri в наших маршрутах в файле -routes.php
Файл Router.php на данный момент полностью:foreach ($this->routes as $uriPattern => $path) { echo "
$uriPattern -> $path"; }
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } //Returns request string private function getURI() { if (!empty($_SERVER['REQUEST_URI'])) { return trim($_SERVER['REQUEST_URI'], '/'); } } public function run() { $uri = $this->getURI(); foreach ($this->routes as $uriPattern => $path) { echo "
$uriPattern -> $path"; } } }
Здесь для каждого маршрута $this->routes
, который находится в нашем массиве,мы помещаем в переменную -$uriPattern
строку запросов из роутов файла- routes.php
(левая часть до => знака), а в переменную $path
- путь обработчика
Перезагружаем страницу и видим:
Теперь мы будем сравнивать строку запроса $uri с данными которые содержатся в роутах- $uriPattern
Это легко сделать используя функцию preg_match()
Для этого мы передаем в нее строку запроса - $uri и данные из наших роутов - $uriPattern
if(preg_match("~$uriPattern~", $uri)) { echo '+'; } }
Сохранили изменения в файле. Заходим на сайт, перезагружаем и получаем:
Причем, если теперь вы введете в строку запроса значение несоответствующее нашим роутам ('news' => 'news/index','products' => 'product/list' ), то ничего не увидите на сайте.
То есть, пока что наш роутер готов обработать два запроса - news и products по определенному правилу.
Обратите внимание, что в качестве разделителей в патерне"~$uriPattern~"
я использовал тильду, так как в нашем патерне могут содержаться слэши- '/' например при таком адресе страницы (' news/archive' => 'news/archive').
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } //Returns request string private function getURI() { if (!empty($_SERVER['REQUEST_URI'])) { return trim($_SERVER['REQUEST_URI'], '/'); } } public function run() { $uri = $this->getURI(); foreach ($this->routes as $uriPattern => $path) { if(preg_match("~$uriPattern~", $uri)) { echo '+'; } } } }
Итак, если условие соблюдается. то в переменной $path будут находиться имя контроллера и экшена. Чтобы в этом убедиться вам нужно заменить + в выводе echo на переменную $path - вот так: echo $path;
Идем на страницу сайта, вводим запрос (существующий) и получаем:
Определяем какой контроллер и экшен обрабатывают запрос
Мы можем это получить с помощью функции - explode(), чтобы разделить строку на две части
Результат вы можете увидеть на скриншоте, а код файла Router.php ниже
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } //Returns request string private function getURI() { if (!empty($_SERVER['REQUEST_URI'])) { return trim($_SERVER['REQUEST_URI'], '/'); } } public function run() { $uri = $this->getURI(); foreach ($this->routes as $uriPattern => $path) { if(preg_match("~$uriPattern~", $uri)) { $segments = explode('/', $path); echo ''; print_r ($segments); echo ''; } } } }
В результате мы получили два элемента, первый относящийся к контроллеру и второй к экшену
Теперь мы можем получить имя контроллера:
$controllerName = array_shift($segments).'Controller';
Здесь мы используем функцию array_shift()
, она получает первый элемент из массива $segments
и удаляет его. К этому значению мы добавляем слово 'Controller', поскольку мы приняли за систему такое именование конроллеров.
теперь нам остается сделать заглавной первую букву в названии контроллера функцией :
$controllerName = ucfirst($controllerName);
И теперь можно сохранить и проверить наш сайт.
Таким образом мы получили контроллер. Точно так же мы получаем и наш экшен, с той лишь разницей, что экшен имеет свой стиль наименований (с добавление вначале слова action, чтобы отличать их от других методов класса.
$actionName = 'action'.ucfirst((array_shift($segments)));
Файл Router.php на данный момент полностью:
<?php class Router { private $routes; public function __construct() { $routesPath = ROOT.'/config/routes.php'; $this->routes = include($routesPath); } //Returns request string private function getURI() { if (!empty($_SERVER['REQUEST_URI'])) { return trim($_SERVER['REQUEST_URI'], '/'); } } public function run() { $uri = $this->getURI(); foreach ($this->routes as $uriPattern => $path) { if(preg_match("~$uriPattern~", $uri)) { $segments = explode('/', $path); $controllerName = array_shift($segments).'Controller'; $controllerName = ucfirst($controllerName); $actionName = 'action'.ucfirst((array_shift($segments))); echo $controllerName.'
'.$actionName; } } } }
Да, кстати, теперь самое время добавить в папку controllers новые файлы ArticleController.php , NewsController.php и ProductController.php
Теперь нам сталось подключить нужный класс, создать его экземпляр и вызвать для определенного класса свой метод.
Вначале нам нужно создать наши контроллеры.
И вот теперь самое время добавить в папку controllers новые файлы ArticleController.php , NewsController.php и ProductController.php
Содержимое файлов NewsController.php и ProductController.php и ArticleController.php это соответствующий класс и один метод, который пустой и просто возвращает - true
NewsController.php
<?php class NewsController { public function actionIndex() { return true; } }
ProductController.php
<?php class ProductController { public function actionList() { return true; } }
ArticleController.php
&jt;?php class ArticleController { public function actionList() { return true; } }
Продолжаем работать над файлом Router.php и далее нам нужно подключить файл класса контроллера. Так как мы уже знаем его имя - $controllerName и используем определенный подход к названию фалов в папке контролеров, то сделать это очень просто вот таким кодом:
$controllerFile = ROOT . '/controllers/' .$controllerName. '.php'; if (file_exists($controllerFile)) { include_once($controllerFile); }
В этой части кода $controllerFile = ROOT . '/controllers/' .$controllerName. '.php';
мы определяем файл который необходимо подключить. Для этого мы прописываем путь к нему используя имя класса
Далее мы непосредственно подключаем его, предварительно проверяя существует ли он?
if (file_exists($controllerFile)) { include_once($controllerFile); }
Все необходимые действия в виде анализа запроса и подключения нужного файла мы выполнили
Создаем объект класса контрллера - $controllerObject = new $controllerName;. Вместо имени класса мы подставляем переменную, которая содержит строку с именем этого класса.
Далее для этого объекта $controllerObject мы вызываем метод $actionName(), точно так же мы используем переменную, которая содержит строку с названием нужного метода. В наших методах в файлах контолерах, мы писали return true для того, чтобы мы могли передать это значение определенной переменной - $result. В рузельтате, если метод сработал, то мы сможем об этом узнать и оборвать весь цикл - if ($result != null) {
break;
}
.
, который ищет совпадения в наших маршрутах.
$controllerObject = new $controllerName; $result = $controllerObject->$actionName(); if ($result != null) { break; }
Теперь наша система практически готова. Осталось добавить несколько штрихов в наши методы контроллеров и проверим ее на работоспособность. Например в NewsController.php (перед return true) - echo "NewsController.php actionIndex ";
Это позволило нам убедиться, что зaпущенн нужный нам метод. Точно тоже мы проделаем и с другим контроллером
Теперь если мы зайдем по другому адресу, мы получим уже совсем другой контроллер с новым экшеном. Если мы зайдем по адресу, которого нет в таблице наших маршрутов (роутах) то мы не получим ничего.
Все файлы проекта можно посмотреть на Гугл Диске
Далее Модель, Представление и усовершенствования класса Роутер
VarangaOfficial - варанга от грибка цена - исключительно достоверные, проверенные факты. Воспользовавшись данным ресурсом, вы получите возможность узнать полную информацию касательно данного лекарственного средства. Лично увидеть данные о проведенных клинических исследований, прочитать отзывы реальных покупателей и врачей. Ознакомиться с инструкцией по применению, прочитать об особенностях и методах работы комплекса, уяснить, в чем заключаются особенности работы крема Варанга, где можно купить оригинальный препарат и, как избежать покупки подделки. Мы очень тщательно и скурпулезно проверяем размещаемые на сайте данные. Предоставляем посетителям нашего онлайн-ресурса сведения, которые были взяты исключительно из надежных источников. Если вы обнаружили у себя признаки грибкового поражения стоп или же долго и безрезультатно пытаетесь избавиться от этого неприятного недуга, наш сайт покажет вам быстрый и простой способ решения проблемы. Присоединяетесь и живите полноценной, здоровой жизнью. Теперь все ответы на самые популярные и волнующие пользователей вопросы, собраны на одном ресурсе.
ОтветитьУдалить