Статьи

Как диспетчеризация работает в OpenCart

Как программист, важно, чтобы вы понимали ход работы системы, с которой работаете, — не только ради возможности что-то изменить при необходимости, но и потому, что это придаст вам уверенности при этом.

Сегодня мы выберем OpenCart и рассмотрим его, чтобы понять основы процесса диспетчеризации. Мы начнем с того, что представляет собой процесс диспетчеризации, и по мере продвижения мы будем исследовать фрагменты кода из различных разделов платформы.

Я подберу последнюю версию OpenCart для этой статьи, но в более ранних версиях процесс более-менее похож.

В любом веб-приложении процесс диспетчеризации используется для поиска соответствия между URL-адресом входящего запроса и соответствующим модулем в платформе. Конечно, реализация варьируется от структуры к структуре, но основная концепция остается неизменной. Итак, вот некоторые из обязанностей диспетчера:

  • Возьмите соответствующие параметры из объекта запроса.
  • Найдите соответствующий модуль и действие, которое нужно вызвать.
  • Если соответствующий модуль и действие найдены, процесс диспетчеризации завершается.
  • Если для данного запроса модуль не найден, устанавливается действие по умолчанию и процесс диспетчеризации завершается.

Давайте попробуем понять это, используя простой пример в OpenCart. Чтобы создать нового пользователя из внешнего интерфейса, необходимо зарегистрироваться на сайте, используя http://www.youropencartstore.com/index.php?route=account/register . Давайте суммируем шаги, предпринятые OpenCart для рендеринга запрошенной страницы.

  • Во-первых, он проверяет наличие переменной строки запроса «route», в противном случае он устанавливает «common / home» в качестве «маршрута» страницы по умолчанию.
  • В нашем случае он присутствует, поэтому он настроит необходимые переменные и запустит процесс отправки.
  • В начале процесса отправки он выполнит некоторые действия «preAction», которые используются для выполнения общих задач. Мы обсудим материал «preAction» в следующей части этой статьи.
  • Наконец, он проверит, доступен ли файл контроллера для текущей переменной «route», и если он есть, он будет вызван для получения ответа.
  • Если для запрошенной переменной «route» нет доступного файла контроллера, он выполнит действие «error / not_found», которое покажет пользователю сообщение «страница не найдена».

Так что это представление верхнего уровня о том, как OpenCart проходит по запрошенному URL и возвращает ответ. В следующем разделе мы пойдем глубже и посмотрим, как именно это происходит.

Продолжайте и откройте файл index.php в корне документа OpenCart. В этом файле много чего происходит, но не перегружайтесь, так как большая его часть — просто настройка объектов, используемых в рамках фреймворка.

Давайте сразу же извлечем интересующий нас фрагмент из этого файла.

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 также опирается на шаблон фронт-контроллера, так что есть общая точка входа для всех запросов в приложении.

Сначала мы создаем экземпляр фронт-контроллера и присваиваем его переменной $controller . Сразу же после этого мы вызываем метод addPreAction чтобы добавить пару действий.

Теперь возникает еще одна тема: что такое «действие»? Проще говоря, предварительное действие — это действие, которое будет выполнено перед запрошенным действием на любой странице. Например, когда пользователь нажимает на любую страницу, вы хотите проверить, находится ли сайт в режиме обслуживания или нет, прежде чем будет возвращен фактический ответ. В этом случае вы можете использовать предварительное действие, чтобы пользователь был перенаправлен на страницу обслуживания, если она включена.

Кроме того, мы добавляем common/seo_url в качестве предварительного действия, поскольку в случае сайта с поддержкой SEO мы хотим получить соответствующие переменные маршрута до начала фактической отправки.

Давайте перейдем к следующему важному фрагменту.

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», и, если она там есть, мы создадим экземпляр класса Action , передав текущее значение «route» в качестве аргумента конструктора. Если его нет, мы сделаем то же самое с URI маршрута домашней страницы — common/home .

С нашей переменной $action установленной с правильным значением, давайте перейдем к следующему фрагменту.

1
2
// Dispatch
$controller->dispatch($action, new Action(‘error/not_found’));

Наконец, мы вызываем метод dispatch класса front controller. Идите вперед, откройте system/engine/front.php и найдите следующий фрагмент.

01
02
03
04
05
06
07
08
09
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);
    }
}

Это метод, где происходит вся магия! Во-первых, он выполняет все «предварительные действия», как обсуждалось ранее. Кроме того, в цикле while он попытается выполнить наше текущее $action , переданное в качестве аргумента метода execute .

Давайте следовать определению метода execute в том же файле.

01
02
03
04
05
06
07
08
09
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-контроллера. Откройте файловую system/engine/action.php и вот она.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public function execute($registry) {
    // Stop any magical methods being called
    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;
    }
}

Здесь важно отметить, что класс Action уже устанавливает обязательные переменные в самом конструкторе, когда объект действия создается в index.php . Он устанавливает свойства file , class и method , которые будут использоваться в методе execute . Чтобы не усложнять ситуацию, мы обсудим только метод execute , хотя я бы порекомендовал вам пройти через конструктор класса Action .

Возвращаясь к нашему методу execute класса Action , он проверяет наличие файла ( $this->file ), связанного с текущим маршрутом. Если все в порядке, он включает этот файл и вызывает соответствующий метод ( $this->method ) этого класса контроллера, используя функцию call_user_func и возвращает ответ.

Если связанный файл недоступен, он вернет false . Теперь вернемся к фрагменту из метода execute класса контроллера Front. Потерпи, мы почти у цели!

01
02
03
04
05
06
07
08
09
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 . Давайте рассмотрим каждый.

Если все прошло нормально, у нас будет вывод HTML в переменной $result , поэтому переменная $action установлена ​​в false и процесс завершается. Это последний случай.

Напомним, что мы вернули false если соответствующий файл контроллера не был найден в методе execute класса Action . В этом случае для переменной $action будет установлено значение $this->error (action / not_found Action ), и пользователю будет показана страница, не найденная.

И наконец, если мы обнаружим, что $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 URL-адрес common/maintenance/info . Конечно, в методе dispatch класса front controller есть код для обработки этого поведения. Вспомните фрагмент этого метода — обещаю, что это последний фрагмент этого урока.

1
2
3
4
5
while ($action) {
    $action = $this->execute($action);
}

Так что это цикл while, и он работает, пока не найдет переменную $action установленную в false ! Более конкретно, он завершит цикл, когда у нас будет полезный вывод для нашего пользователя.

Так что это конец пути. Надеюсь, что это было не так сложно, как казалось на первый взгляд.

Сегодня мы рассмотрели важный аспект инфраструктуры OpenCart — процесс отправки. Мы поняли основы диспетчеризации и прошли весь процесс, чтобы понять, как это работает.

Если вы ищете дополнительные инструменты OpenCart, утилиты, расширения и т. Д., Которые вы можете использовать в своих собственных проектах или для собственного образования, не забудьте посмотреть, что у нас есть на рынке .

По любым вопросам, не стесняйтесь оставлять свои комментарии. Кроме того, Twitter является еще одним вариантом для связи со мной, и я отвечаю быстро.