От автора: как программисту, вам важно понимать принцип работы системы, в которой вы работает, как в ней все устроено. Это нужно не только для того, чтобы уметь вносить изменения в проект по необходимости, но и для большей уверенности в том, что вы все делаете правильно. Сегодня мы поговорим о OpenCart и основных принципах процесса диспетчеризации.
Начнем мы с выяснения, что же такое процесс диспетчеризации, и постепенно перейдем к разбору кусков кода из разных частей фреймворка.
В статье я буду работать с последней версией OpenCart, однако весь процесс в большей своей части не отличается от предыдущих версий.
Коротко о диспетчеризации
В веб-приложениях процесс диспетчеризации отвечает за поиск соответствия входящего запроса URL и соответствующего модуля во фреймворке. Реализация данного процесса в разных фреймворках выполнена по-разному, но основная концепция везде одна и та же. Задачи, которые выполняет диспетчер:
Вытягивает из запрошенного объекта подходящие параметры.
Находит соответствующий модуль и действие на выполнение.
Если модуль и действие найдены, диспетчер прекращает свою работу.
Если по запросу модуль не найден, устанавливается действие по умолчанию, и диспетчер прекращает работу.
Попробуем разобраться в вышесказанном на простом примере в OpenCart. Для создания нового пользователя со стороны front-end’а, необходимо зарегистрировать его на сайте с помощью адреса //www.youropencartstore.com/index.php?route=account/register. Распишем поэтапно процесс рендеринга запрошенной страницы в OpenCart.
Первое, проверяется, а есть ли в адресной строке переменная route. Если ее нет, то для переменной route устанавливается значение по умолчанию «common/home».
В нашем случае переменная есть, а значит, будут заданы нужные переменные и запустится процесс диспетчеризации.
Первым этапом будут запущены так называемые действия «preAction», выполняющие стандартные задачи. Более подробно о preAction’ах мы поговорим в последней части статьи.
В конце проверяется, существует ли файл контроллера для текущей переменной route. Если файл есть, он будет вызван для получения ответа.
Если для запрошенной переменной route нет файла контроллера, будет выполнено действие «error/not_found». У пользователя высветится сообщение «page not found».
Это поверхностный взгляд на то, как OpenCart разбирает запрошенный URL адрес и возвращает ответ. В следующей секции мы более подробно разберем этот процесс.
Подробный разбор процесса диспетчеризации
В корне каталога OpenCart найдите и откройте файл index.php. В этом файле много чего происходит, но не пугайтесь, по большей части там просто задаются объекты, которые потом используются в фреймворке. Сразу же разберем интересующий нас кусок кода.
1 2 3 4 5 6 7 8 |
// Front Controller $controller = new Front($registry); // Maintenance Mode $controller->addPreAction(new Action('common/maintenance')); // SEO URL's $controller->addPreAction(new Action('common/seo_url')); |
Как и большинство других фреймворков, OpenCart работает по шаблону front-controller – для всех запросов в приложении существует единая точка входа, один контроллер обрабатывает все запросы.
Первое, что мы делает, это создаем новый экземпляр единого контроллера и записываем его в переменную $controller. Следующей строкой мы вызываем метод addPreAction и добавляем парочку действий.
Теперь возникает другой вопрос: что такое preAction? Простыми словами, preAction – действие, выполняющееся до запрошенного действия на любой странице. К примеру, когда пользователь кликает на любую страницу, перед возвращением ответа вам нужно проверить, а не находится ли сайт в режиме обслуживания. В таком случае можно использовать preAction, и если сайт находится в режиме обслуживания, пользователя перекинет а страницу со специальным сообщением.
Мы добавили preAction common/seo_url, так как если на сайте активированы SEO адреса, то нам нужно вытянуть соответствующие переменные route еще до старта процесса диспетчеризации. Перейдем к следующему важному куску кода.
1 2 3 4 5 6 |
// Router if (isset($request->get['route'])) { $action = new Action($request->get['route']); } else { $action = new Action('common/home'); } |
Тут проверяется наличие в строке запроса переменной route. Если она есть, то мы передаем текущее значение переменной route в аргумент конструктора и создаем объект класса Action. Если переменной нет, мы делаем то же самое, но уже с домашней страницей — common/home. Задав значение переменной $action, можно переходить дальше.
1 2 |
// Dispatch $controller->dispatch($action, new Action('error/not_found')); |
И наконец, мы вызываем метод dispatch класса контроллера. Откройте файл system/engine/front.php и найдите следующий строки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public function dispatch($action, $error) { $this->error = $error; foreach ($this->pre_action as $pre_action) { $result = $this->execute($pre_action); if ($result) { $action = $result; break; } } while ($action) { $action = $this->execute($action); } } |
В этом методе и происходит вся магия! Сначала выполняются все описанные выше preAction’ы. Далее в цикле while я пытаюсь выполнить наш текущий $action, который передается в качестве аргумента метода execute. Найдем объявление метода execute в этом же файле.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private function execute($action) { $result = $action->execute($this->registry); if (is_object($result)) { $action = $result; } elseif ($result === false) { $action = $this->error; $this->error = ''; } else { $action = false; } return $action; } |
В самой первой строке вызывается метод execute класса Action. Не путайте его с методом execute класса Front controller. Откройте файл system/engine/action.php и найдите:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public function execute($registry) { // Останавливаем все вызванные методы if (substr($this->method, 0, 2) == '__') { return false; } if (is_file($this->file)) { include_once($this->file); $class = $this->class; $controller = new $class($registry); if (is_callable(array($controller, $this->method))) { return call_user_func(array($controller, $this->method), $this->args); } else { return false; } } else { return false; } } |
Тут важно заметить, когда объект действия создается в файле index.php, в конструкторе класса Action уже задаются все нужные переменные. Конкретно, задаются свойства file, class и method, которые потом используются в методе execute. Чтобы не усложнять, мы разберем только метод execute. Но я бы посоветовал вам самим разобраться с конструктором класса Action.
Возвращаясь к нашему методу execute класса Action, он проверяет, есть ли файл ($this->file), относящийся к текущему значению переменной route. Если все нормально, файл подключается, и с помощью функции call_user_func вызывается соответствующий метод ($this->method) класса контроллера и возвращается ответ.
Если файла не существует, возвращается false. Вернемся к коду метода execute класса Front controller. Потерпите, осталось чуть-чуть!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... $result = $action->execute($this->registry); if (is_object($result)) { $action = $result; } elseif ($result === false) { $action = $this->error; $this->error = ''; } else { $action = false; } return $action; ... |
После выполнения метода execute класса Action полученный результат записывается в переменную $result. В переменной $result может храниться 3 возможных результата. Разберем каждый из них.
Если все прошло нормально, в переменной $result будет находиться HTML код, переменная $action задается в false, и процесс диспетчеризации заканчивается. Это случай, когда по коду мы попали в последний блок else.
Вспомните, если соответствующий файл контроллера не найден в методе execute класса Action, то мы возвращали false. В таком случае переменной $action будет присвоено значение $this->error (действие error/not_found), а пользователю покажут сообщение «page not found».
И последнее, если переменная $result является объектом, то мы записываем данный объект в переменную $action. Звучит странно: зачем методу контроллера возвращать другой объект Action, если он должен вернуть HTML код запрошенной страницы? Это просто один из способов контроллера по редиректу пользователей на другой URL.
Давайте откроем файл catalog/controller/common/maintenance.php и по-быстрому пробежимся по нему. При соблюдении определенных условий в методе index возвращается объект Action.
1 2 3 4 5 |
... if (($route != 'payment' && $route != 'api') && !$this->user->isLogged()) { return new Action('common/maintenance/info'); } ... |
Из кода понятно, что метод возвращает объект Action для того, чтобы перенаправить пользователя на страницу common/maintenance/info. В методе dispatch класса Front Controller есть код, который обрабатывает данное перенаправление. Вспомните код из того метода – обещаю, что это последний кусок кода в этом уроке.
1 2 3 4 5 |
... while ($action) { $action = $this->execute($action); } ... |
Это цикла while, который крутится до тех пока, пока $action не будет равна false! Более понятным языком, цикл прекратится, как только у нас будет, что показать пользователю. Вот и конец. Надеюсь, урок был не так сложен, как могло показаться на первый взгляд.
Заключение
Сегодня мы рассмотрели важный процесс во фреймворке OpenCart – процесс диспетчеризации. Мы разобрались с основными моментами и прошли по всему циклу диспетчеризации, чтобы понять принцип его работы.
Автор: Sajal Soni
Источник: //code.tutsplus.com/
Редакция: Команда webformyself.
Комментарии (1)