OpenCart 2+ описание процесса загрузки приложения.
Категория: OpenСart Классы , Архитектура
Для того, чтобы хорошо разбираться в том, с чем работаешь, необходимо знать процесс "изнутри". В данной статье я распишу пошагово процесс работы ядра фреймворка или CMS (кому как нравится) OpenCart версии 2+. Тем более, что OpenCart построен с учетом концепции MVC (модель-вод-контроллер), а значит имеет довольно понятную структуру с которой удобно работать и удобно расширять. Чего пока не хватает - так это документации и русскоязычных статей в интернете.
Файл index.php
Файл находится в корне сайта.
Это точка входа для всего приложения. Все запросы к серверу проходят через этот файл, который подключает нужные библиотеки и координирует дальнейшее выполнение скрипта.
Рассмотрим этапы его работы.
- Устанавливается константа с версией OC
define('VERSION', '2.3.0.2.2');
- При наличии файла config.php в корневой папке, он подключается и устанавливает ряд констант, устанавливающих пути к служебным (system) и рабочим (catalog) папкам, а так же константы доступа к базе данных.
if (is_file('config.php')) {
require_once('config.php');
}
- В случае отсутствия файла config.php в корневой папке, константа DIR_APPLICATION оказывается не установленной. Тогда отсылается заголовок на переадресацию в папку install, которая запускает процесс установки OC и завершает на этом этапе работу скрипта
if (!defined('DIR_APPLICATION')) {
header('Location: install/index.php');
exit;
}
- Если дошли до этой строки - конфигурация загружена, подключается файл из папки system/startup.php
require_once(DIR_SYSTEM . 'startup.php');
- Последняя строка файла index.php
start('catalog');
выполнится лишь после подключения файла 'startup.php', о чем ниже.
Файл system/startup.php
- Устанавливается протоколирование всех ошибок
error_reporting(E_ALL);
- Проверяется версия php, должна быть не ниже 5.4
if (version_compare(phpversion(), '5.4.0', '<') == true) {
exit('PHP5.4+ Required');
}
- Устанавливается временная зона по-умолчанию
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
- Далее устанавливаются значения суперглобального массива $_SERVER
$_SERVER['DOCUMENT_ROOT'] - содержит путь к корневой директории сервера, если скрипт выполняется в виртуальном хосте, в данном элементе указывается путь к корневой директории виртуального хоста.
$_SERVER['REQUEST_URI'] - содержит имя скрипта, начиная от корневой директории виртуального хоста и параметры. Например: /index.php?route=extension/feed/google_sitemapy
$_SERVER['HTTP_HOST'] - доменное имя сайта.
$_SERVER['HTTPS'] - сохраняет в массив признак защищенного соединения HTTPS
- Объявление функции modification(), которая используется для получения пути к
модифицированным файлам CMS (например при подключении дополнений).
function modification($filename) {…}
При этом в начале функции прописаны проверки на область видимости от куда выполняется скрипт – админка, папка install или catalog. Каждая из этих областей видимости определяет свои константы, на основе их и построены данные проверки.
В переменную $file сохраняется путь к файлу начиная от папки system/storage/modification. Если переданный функции файл там найден, то возвращается данный путь. Если нет – значит файл не модифицировался и возвращается тот же путь к файлу, который передан функции в качестве аргумента.
- Подключение файла autoload.php, которого нет по-умолчанию в OpenCart 2.3.
// Autoloader
if (is_file(DIR_SYSTEM . '../../vendor/autoload.php')) {
require_once(DIR_SYSTEM . '../../vendor/autoload.php');
}
В данном файле можно подключить сторонние автозагрузчики или что-то еще.
- Далее код автозагрузки системных классов OC.
Функция spl_autoload_register() при каждом запросе неизвестного класса вызывает функцию library(), которая ищет и загружает запрашиваемый класс из папки system/library или же system/storage/modification/system/library если есть модификация запрашиваемого файла класса, т.к. используется функция modification() для такой проверки.
- Подключается ряд важных системных классов, нужных для работы CMS из папки system\engine.
Экземпляры данных классов будут созданы чуть позже в главном файле фреймворка system\framework.php (описано ниже) и сохранены в реестр для доступа к ним из любого места приложения через загрузчик engine/loader.php.
Предварительно наличие файла проверяется среди модифицированных с помощью функции modification()
require_once(modification(DIR_SYSTEM . 'engine/action.php'));
…
- Из папки system/helper подключается несколько файлов содержащие функции-помошники
- general.php – Файл для обеспечения безопастности. Содержит функцию token() для генерации случайной строки (токена), функцию hash_equals() для сравнения хеш-строк
- utf8.php – устанавливает кодировку
- json.php – кодирует/раскодирует данные в формате json
- В конце данного файла объявление функции start(), которая должна подключить главный файл фреймворка- framework.php, реализующий дальнейшую работу приложения согласно модели MVC.
function start($application_config) {
require_once(DIR_SYSTEM . 'framework.php');
}
После этого, выполнение скрипта возвращается к файлу index.php в котором выполняется последняя строка, запускающая подключение к фалу framework.php
В качестве аргумента, функции передается указатель на рабочий каталог- backend(admin) или frontend(catalog)
start('catalog');
Файл system/framework.php
Не забываем, что все классы в данном файле загружаются с помощью автозагрузчика, с проверкой на модификацию (сначала поиск в папке system/storage/modification/system/…)
- Первой строкой создается объект класса Registry. Файл system\engine\registry.php
$registry = new Registry();
Это самый важный объект приложения. Данный класс используется для хранения(получения, проверки на наличие) в массиве $data служебных объектов (Config, Event, Loader, Request, Response, Database, Session, Cache, Url, Language, Document). Далее в данном файле (framework.php) создаются эти самые служебные объекты и с помощью метода set() сохраняются в закрытой переменной $data класса Registry. Так же, многие из этих объектов, получают Registry в качестве аргумента конструктора, при их создании, для получения доступа из них к реестру, а из него к другим служебным объектам.
Пример.
Любой контроллер наследует от абстрактного класса Controller, который получает объект Registry при создании:
abstract class Controller {
protected $registry;
public function __construct($registry) {
$this->registry = $registry;
}
...
так же есть магические методы
public function __get($key) {
return $this->registry->get($key);
}
public function __set($key, $value) {
$this->registry->set($key, $value);
}
Таким образом, при запросе свойства класса, которое у него отсутствует, идет передача вызова на объект Registry (который был передан в protected $registry).
Таким образом, при вызове в контроллере
$this->load->model('...');
после того, как не будет найдено свойство load контроллера, будет вызвано $registry->load.
То есть, объект Registry используется, в последствии, многими другими объектами для получения доступа к хранимым в нем служебным объектам (их свойствам и методам).
- Config. Файл system\library\config.php
Данный объект собирает массив настроек (private $data) для различных частей приложения. Он имеет три метода для сохранения, получения и проверки наличия определенной настройки.
Сразу после создания объекта, вызывается метод загрузки конфигурации из файла system\config\default.php
$config->load('default');
в данном файле хранятся настройки по умолчанию касающиеся БД, эл.почты, вывода ошибок, сессии, кэша, кодировки и др. (см. файл system\config\default.php)
Следующей строкой в массив настроек добавляются настройки из файла
- system\config\catalog.php (если фреймворк запущен из frontend – в index.php строкой start('catalog');)
или
- system\config\admin.php (для админки)
Затем, экземпляр класса Config сохраняется в массив $data класса Registry
Данные одного из этих файлов (который загрузится) дополняет и где-то меняет настройки по-умолчанию из файла default.php
- Event. Файл system\engine\event.php
Объект данного класса работает с событиями OC. События используются для вставки своего кода в существующий на определенном этапе его выполнения.
Строкой
$event = new Event($registry);
передается объект Registry в конструктор класса Event, для использования в методе trigger() при вызове нужных функций.
- Event Register. Регистрируюся все события, которые были получены объектом Config и сохранены в массиве action_event. Они записываются в массив data[$trigger] объекта Event.
if ($config->has('action_event')) {
foreach ($config->get('action_event') as $key => $value) {
$event->register($key, new Action($value));
}
}
- Loader. Файл system\engine\loader.php
Объект позволяет загрузить нужные классы controller, model, view, language, а так же служебные классы из папок library, helper, config
Экземпляр класса Loader сохраняется в массив объекта Registry с ключем 'load', поэтому доступен как load.
Пример загрузки из класса контроллера:
$this->load->model('account/custom_field');
Делает он это, опять таки, с помощью переданного ему, в качестве аргумента для конструктора, объекта Registry, хранящему все служебные объекты с их свойствами (читать выше).
- Request (запрос браузера на сервер). Файл system\library\request.php
Данный класс сохраняет в своих свойствах элементы глобальных массивов (_GET _POST _REQUEST _COOKIE _FILES _SERVER), пропуская, предварительно, ключи и значения через метод clean(), которая преобразует специальные символы в HTML-сущности.
С помощью данного класса, обращаться к элементам суперглобальных массивов можно так:
$this->request->post['address_id']
в результате будет получено значение массива $_POST по ключу 'address_id'.
- Response (ответ сервера браузеру). Файл system\library\response.php
После создания объекта Response, следующей строкой, создается заголовок с кодировкой по-умолчанию.
$response->addHeader('Content-Type: text/html; charset=utf-8');
В данный объект можно сохранять свои заголовки методом addHeader($header), которые будут добавляться в private $headers.
Есть так же метод для переадресации redirect($url, $status = 302), метод для сжатия страницы сервером перед отправкой браузеру compress().
Метод setOutput($output) вызывается во многих контроллерах для сохранения страницы (после формирования файла представления) в private $output объекта Response, для последующего вывода:
$this->response->setOutput($this->load->view('checkout/checkout', $data));
Метод output() – передает браузеру для вывода заголовки и все содержимое страницы. Он выполняется в самом конце файла framework.php
- DB. Класс для работы с базой данных. Файл system\library\db.php
При создании объекта проверяется существование класса, отвечающего за работу с указанным расширением (указывается в конфиге, в массиве «db_type» - например mysqli). Если класс найден, на основании других данных из конфига создается соединение с БД.
Данный объект используется в моделях:
$this->db->query("INSERT INTO…
- Session. Класс для работы с сессиями. Файл system\library\session.php
В настройках проверяется нужно ли сразу стартовать сессию (для каталога admin стартует сразу)
В конструкторе класса Session есть строка определяющая параметры для куки сессии
session_set_cookie_params(0, '/');
ноль значит, что при закрытии браузера куки удалятся (например товары из корзины). Поэтому можно установить свое значение в секундах.
Так же с сессиями работают:
- класс Session\DB из файла system\library\session\db.php который сохраняет определенные данные в БД устанавливая в одно из полей идентификатор текущей сессии (нужно предварительно раскомментировать код создания таблицы session в начале файла);
- класс Session\File из файла system\library\session\file.php который создает файл имеющий название '/sess_' + идентификатор сессии и сохраняет в него данные.
Идентификатор сессии, данные классы, получают из класса Session с помощью метода getId()
- Cache. Класс для работы с кэшем. Файл system\library\cache.php
Данный класс подключает один из файлов, который определяет место хранения кэша. Место хранения передается конструктору при создании объекта в качестве аргумента $adaptor.
Возможные способы хранения кэша:
- APC (system\library\cache\apc.php)
- Файл (system\library\cache\file.php)
- Оперативная память (system\library\cache\mem.php)
По умолчанию в настройках стоит хранение кэша в файле и срок 3600 (1 час)
Методы работы с кэшем get() set() delete(), в зависимости от указанного места хранения, перенаправляются к одному из соответствующих классов.
- Url. Объект данного класса генерирует URL (ссылки). Файл system\library\url.php
Методу link() передаются параметры из которых он формирует и возвращает полный URL.
$data['customlink'] = $this->url->link('custom/custom');
- Language. Файл подключающий языковые файлы и получающий из них запрашиваемую строку. Файл system\library\language.php
Язык используемый по-умолчанию, прописывается в файле конфигурации system\config\default.php:
$_['language_default'] = 'en-gb';
Метод load данного класса, принимает, в качестве первого аргумента путь к файлу перевода, который подключается:
$this->load->language('checkout/checkout');
В данной строке, load является не методом класса language, а объектом класса Loader, который содержит метод language(), вызывающий (через регистратор объектов- Registry) метод load уже объекта language, передавая ему параметры в скобках.
Получение данных из массива подключаемого языкового файла осуществляется с помощью метода get():
$this->language->get('heading_title')
- Document. Объект данного класса содержит данные (собирает и возвращает) выводимые в основном в шапке HTML документа, такие как заголовок страницы, описание, ключевые слова, стили, js скрипты и др. Файл system\library\document.php
Методы класса состоят из get – получающих значение элемента и set(add) устанавливающих значение или массив значений. Таким образом можно, например добавить свой файл стилей в массив:
$this->document->addStyle('catalog/view/mystyle.css');
далее, в контроллере получаем все стили и передаем в представление (header.tpl), где в цикле они извлекаются.
- Config Autoload. Производится автозагрузка конфигурационных файлов, которые можно добавить в system\config\admin.php
Данные файлы нужно указать в system\config\default.php в массиве
// Autoload Configs
$_['config_autoload'] = array();
- Language Autoload. Загружает автоматически языковые файлы, указанные в system\config\default.php
$_['language_autoload'] = array('en-gb');
- Library Autoload. Позволяет автоматически загрузить указанные классы библиотек. Например для frontend загружается дополнительно библиотека openbay, указанная в файле system\config\catalog.php
$_['library_autoload'] = array(
'openbay'
);
- Model Autoload. Позволяет автоматически загрузить модель из списка указанном в конфигурационных файлах, например в system\config\default.php
$_['model_autoload'] = array();
- Front Controller. Объект используется для выполнения переданных ему действий (вызов определенного метода нужного контроллера) до выполнения метода контроллера переданного в route (полученного из URL).
$controller = new Front($registry);
Создается объект класса Front хранящий обработчики событий в массиве (private $pre_action) и вызывающий для их обработки метод execute объекта Action. Файл system\engine\front.php
Метод addPreAction() формирует массив объектов класса Action для последующего выполнения.
Метод dispatch() сначала выполняет все элементы из массива $pre_action, а затем переданный в качестве аргумента Action $action. Для выполнения он передает объекты методу execute(), где вызывается одноименный метод объекта Action, который и выполняет метод (по-умолчанию index) переданного ему контроллера.
- Pre Actions. В данном блоке, в фронт-контроллер устанавливаются действия, которые должны выполняться до выполнения любых других действий.
if ($config->has('action_pre_action')) {
foreach ($config->get('action_pre_action') as $value) {
$controller->addPreAction(new Action($value));
}
}
В конфигурационном файле проверяется наличие действий (контроллеров), методы (index) которых нужно выполнить сразу же. Например в system\config\catalog.php:
$_['action_pre_action'] = array(
'startup/session',
'startup/startup',
'startup/error',
'startup/event',
'startup/maintenance',
'startup/'.$seo_type
);
В цикле, данные массива передаются в метод addPreAction() объекта Front, где они сохраняются в массив $pre_action для дальнейшего выполнения.
- Dispatch. Данная строка кода:
$controller->dispatch(new Action($config->get('action_router')), new Action($config->get('action_error')));
отправляет на выполнение объект Action с аргументом из конфигурационного файла (startup/router.php) и вторым аргументом объект с указанием файла который должен обработать ошибки, если будут. В данном случае это «error/not_found»
То есть вызов метода $controller->dispatch() в OC начинает процесс работы контроллера/метода указанных в route в данный момент (из URL), перед этим выполнив методы (index по-умолчанию если не указаны другие) данных классов (из 'action_pre_action'):
'startup/session',
'startup/startup',
'startup/error',
'startup/event',
'startup/maintenance',
'startup/'.$seo_type
Указанные контроллеры находятся в папке catalog\controller\startup
Выполнив предварительные методы из списка, последним в списке вызывается catalog\controller\startup\router.php
он из URL отбирает только значение «route»- контроллер/действие и создает объект класса Action передав ему их в качестве аргумента для конструктора. Далее вызывается метод execute() объекта Action, который и выполняет переданные ему контроллер/метод. Остальные GET параметры используются уже в этих контроллерах.
$response->setCompression($config->get('config_compression'));
Считывается из конфигурации и сохраняется в свойстве объекта Response уровень сжатия для функции gzencode(). По умолчанию – 0 (без сжатия).
Завершающая строка выполняемая фреймворком
$response->output();
Вызывает метод output() объекта Response, в котором производится вызов метода сжатия compress() если до этого был выбран уровень сжатия, затем отсылаются заголовки и выводится контент строкой echo $output;
Стоит еще вспомнить класс Action, который был подключен в файле system/startup.php. Файл system\engine\action.php
Объект его создается в основном в данном файле (framework.php) когда нужно выполнить какой-то метод определенного контроллера. При создании его объекта, конструктору передается $route – путь к выполняемому контроллеру/метод. Если метод не передан – будет выполняться метод index.
В файле framework.php объект класса Action передается
- для выполнения методов служебных объектов (предзагрузки) массива 'action_pre_action' файла конфигурации
- методу dispatch() объекта Front Controller, который сначала в цикле выполняет действия добавленные в предзагрузку и затем действие(контроллер) startup/router, который разбирает текущий URL и выполняет указанный там контроллер/действие.
Автор: Сергей Дата публикации: 18.04.2017
Другие статьи:
- Процесс вывода страницы в OpenCart согласно полученного URL.
- События в OpenCart 2.2+
- Модуль вывода категорий для OpenCart 2.3. Процесс создания модуля.
- Класс Action в OpenCart 2.
- Регистратор объектов в OpenCart 2. Класс Registry.
Комментарии (без регистрации)
- Антон 14.05.2018 10:07
Спасибо за статью. Первый раз вижу настолько подробную статью о работе фреймверка opencart, хоть и давно работаю с ним. Ответить
Добавление новых комментариев временно отключено.
Рубрики
- PHP
- Yii2
- Laravel
- Symfony
- OpenСart
- Разное
Метки
Сессии Логи Пагинация Рассылка Composer Расширения/пакеты Архитектура actions Тестирование Поиск Apache События Ajax Карта сайта behaviors URL API Сервер Виджеты Аутентификация Кэш REST Авторизация Шаблон Модули БД MySQL Разное Debug Фильтры Классы Мультиязычность Контроллер Git функции Меню Ошибки/исключения Подписка