Показаны сообщения с ярлыком Как оно тикает. Показать все сообщения
Показаны сообщения с ярлыком Как оно тикает. Показать все сообщения

вторник, 1 января 2013 г.

Шаблоны в OpenCart

OpenCart построен на основе концепции MVC, но я бы ее переименовал в MTC, поскольку вид в опенкартовской реализации этой концепции – сущность совершенно пассивная. Это шаблон, который тупо заполняется данными сформированными контроллером. Даже расширение используется “tpl” как сокращение от template. Хотя по сути это обычный php. А внутри куча “echo $variable” в перемешку с HTML и JavaScript. Последний, к слову сказать, не грех бы отделить.

Насколько логична и интуитивно понятна программная реализация OpenCart, настолько же мозголомной является часть относящаяся к дизайну. Т.е. если в других CMS вы можете сварганить на чистом HTML “рыбу”, а затем вставить в нее куски кода, то здесь вам придется эту рыбу выпотрошить и раздербанить на кучу мелких шаблончиков. А чтобы понять из каких кусочков собирается конкретная страница – придется смотреть  не только на ее “маршрут”, но и заглянуть в код контроллера, который за этот маршрут отвечает и код его “детишек”. А может быть еще и в админскую часть магазина (некоторые модули имеют в настройках имя используемого шаблона).

Мысль: для упрощения работы по скрещиванию дизайна с магазином, дизайн нужно делать в виде набора SHTML файлов совпадающего по своей структуре с набором шаблонов. Т.е. обязательное требование к дизайнеру/верстальщику – наличие элементарных знаний SSI. Ну и естественно необходимо начать с описания этой самой структуры.

воскресенье, 30 декабря 2012 г.

OpenCart: Резервы быстродействия

Вчера я кратко упоминал о  том, что сходу наткнулся на 3 запроса к БД которые не вредно бы кэшировать. Сегодня я это сделал, пока начерно, не задумываясь о красоте кода. И естественно возжелал узнать, а много ли от этого проку. Как выяснилось – немного. Результат был меньше статистической погрешности, иными словами каждый запуск теста давал иное значение и разброс этих  значений был больше эффекта от кэширования этих 3ех запросов. Должен отметить, что такой результат меня смутил. Я усомнился, стоит ли городить огород и есть ли польза встроенного в OpenCart механизма кэширования, он, кстати, достаточно скромный. Это файловый кэш и увеличивая объем кэшированных данных мы по сути подменяем механизмы поиска БД, механизмами поиска файловой системы и еще вопрос, какие из них лучше оптимизированы.

Однако, чуть позже я задумал посмотреть, а какие вообще запросы к БД выполняются и какой процент из них кэшируется. Не мудрствуя лукаво добавил пару строк в класс DB

class DB {
    private $driver;
    private $log;
   

public function __construct($driver, $hostname, $username, $password, $database) {
    …       
    $this->log = new Log("dblog");
}

    public function query($sql) {
        $this->log->write($sql);
        return $this->driver->query($sql);
      }

Результат обескураживает. Первый вывод страницы – 99 обращений к БД. Второй и последующие – 91.

Из них 3 исключаются за счет моих усилий (на самом деле 2, я не учел какие-то нюансы с первым магазином, а может что-то на портачил во время возни с мультимагазином ) еще 6 кэшируются движком OpenCart, а остальные 91 (!) выполняются при каждой (!!!) загрузке главной страницы.

Причем например такой запрос:

SELECT * FROM test_extension WHERE `type` = 'module'

Выполняется за время загрузки одной страницы 4 (!) раза. И вот такой:


SELECT * FROM test_layout_route WHERE 'common/home' LIKE CONCAT(route, '%') AND store_id = '0' ORDER BY route ASC LIMIT 1


тоже 4 раза! Вот эти запросы:

SELECT * FROM test_currency
SELECT * FROM test_weight_class wc LEFT JOIN test_weight_class_description wcd ON (wc.weight_class_id = wcd.weight_class_id) WHERE wcd.language_id = '2'
SELECT * FROM test_length_class mc LEFT JOIN test_length_class_description mcd ON (mc.length_class_id = mcd.length_class_id) WHERE mcd.language_id = '2'

Выдают информацию которая изменяется дай бог если несколько раз за все время существования магазина. Выдача этого запроса тоже меняется лишь чуть чаще чем никогда:


SELECT * FROM test_extension WHERE `type` = 'total'


Короче ужос, просто тихий  ужос. Оптимизировать, оптимизировать и еще раз оптимизировать. Перешел на страницу продукта. 161 запрос. Вторая и последующие загрузки -  156. Смотрим:


SELECT * FROM test_currency - 3 раза


Мама… роди меня обратно.

суббота, 29 декабря 2012 г.

OpenCart: А внутре у ей неонка

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

Все запросы к магазину с помощью .htaccess направляются на index.php. Кроме админки и установки. Для них в соответствующих каталогах (admin и install) предусмотрена своя точка входа. Логично – админка и установка имеют свой интерфейс имеющий мало общего с магазином и стало быть не зачем мешать их в кучу. Их я пока не касаюсь, ниже пойдет речь только о магазине.

Итак, что у нас в index.php:

1. Загружаем config.php

Он был создан при установке, в нем определены глобальные переменные, которые указывают где что лежит и как достучаться до БД. Если выясняется что установка еще не производилась (отсутствует DIR_APPLICATION), то производится перенаправление на install/index.php

2. Подгружаются разные всякие библиотеки необходимые для работы

В system/startup.php вынесена загрузка библиотек “низкого” уровня, высокоуровневые библиотеки загружаются в index.php. Думаю такое разделение связано с тем что первые изначально унаследованы от какой-то другой системы, а вторые в те далекие времена и составляли собственно OpenCart. Обычная практика.

3 Создаются экземпляры классов Registry, Loader, Config, DB

Все названия что называется говорят сами за себя. Я пока не совсем понимаю чем занимается Loader, со всеми остальными вопросов не возникает

DB инкапсулирует операции с базой данных, в конфиг чуть позже будут загружены всевозможные настройки,  хранимые в БД, а Registry – это сборная солянка, реестр, который содержит в себе ссылки на всё что только можно. Тем самым мы избавляемся от глобальных переменных, но при необходимости может вытащить все что угодно из реестра. Все упомянутые здесь и ниже объекты заталкиваются в реестр.

4. По URL определяем магазин – ведь в базе у нас их может быть несколько

5. Загружаем из БД настройки магазина, при необходимости распаковываем сериализованные.

6. Устанавливаем обработчик ошибок

Хм… т.е. если ошибка произойдет раньше, то в лог магазина ничего не запишется, разве только в лог сервера. Это нужно помнить и контролировать и то и другое. Хотя на мой взгляд лучшее решение – вынести настройки логирования в config.php, а установку обработчика ошибок перенести ближе к началу файла.

7. Готовим объекты Request, Responce, Cache и Session

Не знаю пока что там у нас кэшируется, но выходит что 2 запроса к БД выполняются до того как мы вообще вспоминаем про кэширование. И такое впечатление что и дальше как минимум один запрос также выполняется без кэширования. Т.е. любая страница – это уже минимум три запроса к БД. Причем все три абсолютно одинаковые для всех страниц. Результат одного из них не меняется вообще никогда. А результаты двух меняются крайне редко – мы же не каждый день меняем настройки, а языки добавляем и того реже.

8. Определяем язык в соответствии с настройками браузера и данными сессии

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

9. Создаются объекты Document, Customer, Affiliate, Currency, Tax, Weight, Length, Cart, Encryption

Назначение большей части из них достаточно очевидно.

10. Создается и настраивается  контролер входа (Front controller), выбирается маршрут (route)

Маршрут содержится в URL.  Если нет – используется маршрут по умолчанию “common/home”

11. Контроллер осуществляет разбор полетов в соответствии с маршрутом . На случай если что-то пойдет не так, ему передается запасной маршрут “error/not_found”

12. Результат выводится

 

З.Ы. Все это несколько сумбурно и невразумительно. Поэтому интересующимся я настоятельно рекомендую для начала почитать вот это.