Файл с данным классом подключается одним из первых на этапе загрузки приложения в файле system\startup.php:
require_once(modification(DIR_SYSTEM . 'engine/action.php'));<span class="redactor-invisible-space"></span>
и используется при вызове стандартных событий OpenCart, подключаемых в файле system\framework.php строкой
if ($config->has('action_event')) { foreach ($config->get('action_event') as $key => $value) { $event->register($key, new Action($value)); } }далее в этом же файле, для выполнения стандартных действий из папки controller\startup:
if ($config->has('action_pre_action')) { foreach ($config->get('action_pre_action') as $value) { $controller->addPreAction(new Action($value)); } }а так же для выполнения всех других контроллеров(методов) , например действий согласно разбора текущего URL.
Основные задачи, выполняемые объектом класса Action:
- разбор переданного методу-конструктору параметра $route. Определение названия и пути к нужному контроллеру и метода, который необходимо вызвать;
- выполнение данного метода контроллера (используется класс Reflection API) с возвратом полученного результата.
Далее код данного класса с подробнейшим описанием (файл system\engine\action.php)
<?php //DIR_APPLICATION - константа для указания директории с папкой контроллеров из файла config.php define('DIR_APPLICATION', ''); class Action { private $id; private $route; private $method = 'index'; public function __construct($route) { /* Разбирает $route типа common/fun/get на элементы массива по разделителю "/" [0] => common [1] => fun [2] => get */ $parts = explode('/', preg_replace('/[^a-zA-Z0-9_\/]/', '', (string)$route)); //Цикл выполняется пока $parts = true или выполняется оператор break; while ($parts) { /* * Формирует строку элементов массива добавляя спереди и после символы * результат: ./controllers/common/fun/get.php */ $file = DIR_APPLICATION . 'controller/' . implode('/', $parts) . '.php'; if (is_file($file)) { //Если файл найден - формирует строку типа common/fun и сохраняет $this->route = implode('/', $parts); break; } else { /* * Если файл не найден - значит последний элемент массива - название метода * Сохраняем последний элемент и удаляем его из массива $parts */ $this->method = array_pop($parts); } } } public function getId() { return $this->id; } /* * $registry - в Opencart используется для передачи в конструктор создаваемого * объекта (контроллера) - объекта-регистратора, для доступа через него к методам * других объектов * $args - аргументы для вызываемого метода */ public function execute($registry=null, array $args = array()) { // Не разрешаем вызов магических методов if (substr($this->method, 0, 2) == '__') { return new \Exception('Ошибка: Запрещены вызовы к магическим методам!'); } //Формируем путь к файлу $file = DIR_APPLICATION . 'controller/' . $this->route . '.php'; //Формирует название класса контроллера. Получается Controllercommonfun $class = 'Controller' . preg_replace('/[^a-zA-Z0-9]/', '', $this->route); if (is_file($file)) { include_once($file); //подключаем файл контроллера $controller = new $class($registry); //создаем экземпляр класса контроллера } else { return new \Exception('Ошибка: Невозможно вызвать ' . $this->route . '/' . $this->method . '!'); } //Создаем экземпляр класса Reflection API для получения информации о интересующем классе $reflection = new ReflectionClass($class); /* * Проверяем задан ли указанный метод, а так же проверяем, чтобы у этого метода кол-во обязательных аргументов * не превысило те, которые были переданы */ if ($reflection->hasMethod($this->method) && $reflection->getMethod($this->method)->getNumberOfRequiredParameters() <= count($args)) { //Вызываем метод $this->method объекта $controller с массивом аргументов $args return call_user_func_array(array($controller, $this->method), $args); } else { return new \Exception('Ошибка: Невозможно вызвать ' . $this->route . '/' . $this->method . '!'); } } }
Для демонстрации работы объекта класса Action, я создал парочку действий. Аналогично тому, что происходит в OpenCart, они передают в метод-конструктор при создании объекта параметр состоящий из
[путь к файлу контроллера] [название класса контроллера] [метод который нужно выполнить]
Стоит отметить, что в OpenCart, большинство классов контроллеров состоит из единственного метода "index". Поэтому предусмотрена возможность не указывать метод, если он является методом "по-умолчанию". Это продемонстрировано в первом примере.
Во-втором примере вызываем определенный метод нужного контроллера с передачей ему массива аргументов.
Результат вызовов будет отображен на экран.
Если вы захотите протестировать данный класс, можно скачать архив с файлами этих классов.
/* * 1. Простой вызов действия. Выполнится метод по-умолчанию - index */ $action = new Action('common/fun'); $output = $action->execute(); echo $output . '<br>'; //Выполнен метод index /* * 2. Если нужен не метод по-умолчанию - указываем явно */ $action = new Action('common/fun/get'); /* * В массиве первым элементом можно передать аргумент для метода конструктора создаваемого экземпляра * класса контроллера * Вторым элементом передаются аргументы для метода (в массиве) */ $output = $action->execute(null, [10]); echo $output; //Выполнен метод get. Значение 10
Файл controller\common\fun.php с примитивным классом контроллера для тестирования
<?php /* * Для динамического формирования имени в методе execute() класса Action, * Имя должно состоять из Controller[путь к файлу][название] */ class ControllerCommonFun { function index(){ return 'Выполнен метод index'; } function get($date){ return "Выполнен метод get. Значение $date"; } }