You are using an outdated browser. For a faster, safer browsing experience, upgrade for free today.

Ako zrýchliť modul pre internetový obchod OpenCart

Možno ste nainštalovali modul pre OpenCart 3 a po jeho zapnutí sa stránka, na ktorej sa modul vykresľuje, výrazne spomalila. Častou príčinou býva to, že modul pri každom načítaní znovu skladá tie isté dáta z databázy. Riešením býva doplnenie dátovej cache do system/storage/cache/.

Tento návod opisuje všeobecný a bezpečný postup pre moduly tretích strán v OpenCart 3. Je zameraný na situáciu, keď modul na frontende opakovane generuje rovnaký výstup a jeho výpočet je zbytočne náročný.

Ako funguje file cache v OpenCart 3

OpenCart má vstavanú triedu Cache. Ak je použitý adaptér file, dáta sa ukladajú do súborov v priečinku system/storage/cache/.

Priebeh je zvyčajne takýto:

  • Prvá požiadavka: Modul vypočíta dáta, uloží ich do cache a vráti výstup.
  • Ďalšie požiadavky: Modul sa najskôr pokúsi načítať dáta z cache. Ak existujú, znovu nevykonáva náročné SQL dotazy ani ďalšiu náročnú logiku.
  • Expirácia: Pri file cache v OpenCarte nie je potrebné ukladať vlastný timestamp do dát. Expirácia je súčasťou názvu cache súboru a rieši ju samotná knižnica cache.
  • Invalidácia: Keď sa zmení nastavenie modulu alebo zdrojové dáta, je potrebné príslušnú cache zmazať metódou $this->cache->delete(...).

Kedy sa tento postup hodí

Typicky vtedy, keď modul na frontende opakovane:

  • načítava kategórie, produkty alebo iné zoznamy z databázy,
  • zostavuje zložité viacrozmerné polia, HTML bloky alebo stromové štruktúry,
  • volá viac modelov vo vnútri niekoľkých vnorených cyklov,
  • vracia rovnaký výsledok pre mnohých návštevníkov.

Naopak opatrnosť je potrebná pri moduloch, ktorých výstup závisí od konkrétneho zákazníka, košíka, prihlásenia, meny, aktívnej kategórie, jazyka alebo iného kontextu. V takom prípade musia byť tieto hodnoty súčasťou cache kľúča, alebo sa daná časť nesmie cachovať vôbec.

Krok 1: Nájdite časť frontend controlleru, ktorá server najviac zaťažuje

Otvorte controller modulu, najčastejšie v ceste catalog/controller/extension/module/[nazov_modulu].php.

Zvyčajne hľadáte metódu index($setting) alebo podobnú hlavnú metódu. Cieľom je obaliť cache iba tú časť, ktorá pripravuje dátové pole pre šablónu. Bežné načítanie jazyka, pripojenie JS/CSS alebo iné ľahké operácie môžu zostať mimo cache.

Krok 2: Zostavte správny cache kľúč

Kľúč musí rozlíšiť všetky stavy, v ktorých môže mať modul iný výstup. Nestačí len názov modulu. Často je potrebné zahrnúť napríklad:

  • nastavenie konkrétnej inštancie modulu v parametri $setting,
  • store_id, ak máte viac obchodov,
  • language_id, ak modul vypisuje preklady alebo lokalizované dáta,
  • customer_group_id, ak sa líšia ceny alebo viditeľnosť produktov,
  • theme, ak sa dátová štruktúra líši podľa šablóny,
  • path, product_id, manufacturer_id alebo iný parameter URL, ak sa podľa neho menia aktívne položky alebo obsah modulu.

Bezpečný všeobecný vzor:

$cache_key = 'module_[nazov_modulu].' . md5(json_encode(array(
    'setting'           => $setting,
    'store_id'          => (int)$this->config->get('config_store_id'),
    'language_id'       => (int)$this->config->get('config_language_id'),
    'customer_group_id' => (int)$this->config->get('config_customer_group_id'),
    'theme'             => $this->config->get('theme_' . $this->config->get('config_theme') . '_directory'),
    'path'              => isset($this->request->get['path']) ? (string)$this->request->get['path'] : ''
)));

Ak výstup od path alebo iných URL premenných nezávisí, do kľúča ich nedávajte. Zbytočne by ste si rozdelili cache do mnohých súborov.

Krok 3: Najskôr skúste načítať dáta z cache

Na začiatok náročnej časti vložte kontrolu cache. Ak dáta existujú, rovno ich použite.

$cache_data = $this->cache->get($cache_key);

if ($cache_data) {
    return $this->load->view('extension/module/[nazov_modulu]', $cache_data);
}

Tu je dôležité, že ukladáte priamo finálne dátové pole pre šablónu, typicky premennú $data. OpenCart file cache už sama rieši životnosť súboru, takže nie je potrebné do cache ukladať ďalšie pole typu expire alebo ttl.

Krok 4: Ponechajte pôvodnú logiku modulu a uložte výsledné dáta

Pôvodný náročný kód zostane prakticky bez zmeny. Len po jeho dokončení uložíte finálne dáta do cache.

// Ak cache neexistuje, prebehne pôvodná logika modulu:
// - načítanie kategórií
// - načítanie produktov
// - skladanie stromu
// - príprava poľa $data pre twig

$this->cache->set($cache_key, $data);

return $this->load->view('extension/module/[nazov_modulu]', $data);

Tým dosiahnete, že prvý návštevník výstup vypočíta a ďalší už dostanú hotové dáta z cache súboru.

Krok 5: Invalidácia cache po zmene nastavenia modulu

Otvorte administrátorský controller modulu, zvyčajne admin/controller/extension/module/[nazov_modulu].php.

Po uložení nastavenia vložte zmazanie cache. Odporúčaný postup je mazať spoločný prefix, nie konkrétny hash.

$this->cache->delete('module_[nazov_modulu]');

Pri file cache v OpenCarte sa tým zmažú všetky súbory začínajúce týmto prefixom, napríklad cache.module_[nazov_modulu].abc123.... To je dôležité, pretože jednotlivé varianty modulu bývajú rozlíšené hashom podľa jazyka, obchodu, nastavenia alebo URL kontextu.

Krok 6: Invalidácia aj pri zmene zdrojových dát

Samotné uloženie nastavenia modulu často nestačí. Ak modul zobrazuje produkty, kategórie, výrobcov, recenzie alebo iné dáta z administrácie, je vhodné mazať cache aj pri zmene týchto dát.

Príklady:

  • modul pracujúci s produktmi: mazať cache po uložení alebo zmazaní produktu,
  • modul pracujúci s kategóriami: mazať cache po zmene kategórie,
  • modul so značkami alebo blogom: mazať cache pri úprave zodpovedajúcich záznamov.

Inak sa môže stať, že modul zostane funkčný a rýchly, ale bude určitý čas zobrazovať zastarané dáta až do expirácie cache.

Krok 7: Ako dlho cache žije

V štandardnom OpenCart 3 je pri file cache bežná životnosť často 3600 sekúnd, teda 1 hodina. Táto hodnota sa odovzdáva pri vytvorení inštancie cache a file adaptér ju zapisuje do názvu súboru.

Praktický dôsledok:

  • po uplynutí času sa cache súbor považuje za expirovaný,
  • staré súbory sa priebežne mažú pri práci s cache,
  • nie je potrebná vlastná ručná práca s timestampom vo vnútri uložených dát.

Krok 8: Ako cache ručne vyčistiť pri testovaní

Pri ladení alebo testovaní môžete cache odstrániť aj ručne v priečinku system/storage/cache/.

  • Ručné zmazanie konkrétnej skupiny: zmažte súbory začínajúce na cache.module_[nazov_modulu].
  • Zmazanie po uložení v administrácii: ak ste správne doplnili $this->cache->delete(...), cache sa zmaže sama pri uložení modulu
  • Automatická expirácia: ak nič nemažete, stará cache sama prestane platiť po uplynutí nastavenej doby

Poznámka: v niektorých inštaláciách OpenCartu tlačidlá na vyčistenie vývojárskych cache riešia hlavne Twig, SASS alebo modification cache. Dátovú file cache modulu je istejšie mazať priamo cez $this->cache->delete(...) alebo ručne v priečinku system/storage/cache/.

Najčastejšie chyby

  • Príliš všeobecný cache kľúč: modul potom vracia nesprávny obsah pre iný jazyk, iný obchod alebo inú stránku.
  • Príliš detailný cache kľúč: cache sa zbytočne triešti a prínos sa znižuje.
  • Chýbajúca invalidácia: modul je rýchly, ale po úpravách v administrácii zobrazuje staré dáta.
  • Cachovanie per-customer výstupu: môže dôjsť k zobrazeniu nesprávnych dát inému zákazníkovi.
  • Cachovanie príliš skoro: ak do cache uložíte nedokončené dáta alebo výstup závislý od ďalšej logiky, výsledok môže byť nekonzistentný.

Odporúčaný všeobecný vzor

public function index($setting) {
    $this->load->language('extension/module/[nazov_modulu]');

    $cache_key = 'module_[nazov_modulu].' . md5(json_encode(array(
        'setting'           => $setting,
        'store_id'          => (int)$this->config->get('config_store_id'),
        'language_id'       => (int)$this->config->get('config_language_id'),
        'customer_group_id' => (int)$this->config->get('config_customer_group_id')
    )));

    $cache_data = $this->cache->get($cache_key);

    if ($cache_data) {
        return $this->load->view('extension/module/[nazov_modulu]', $cache_data);
    }

    $data = array();

    /* === TU ZAČÍNA PÔVODNÁ NÁROČNÁ LOGIKA MODULU === */
    /* načítanie modelov, SQL dotazy, cykly, skladanie výstupných dát */
    /* === TU KONČÍ PÔVODNÁ NÁROČNÁ LOGIKA MODULU === */

    $this->cache->set($cache_key, $data);

    return $this->load->view('extension/module/[nazov_modulu]', $data);
}

Praktická poznámka k modulu s viacerými inštanciami

Ak sa rovnaký modul používa na viacerých layoutoch alebo vo viacerých inštanciách, je veľmi dôležité, aby bol súčasťou kľúča aj obsah $setting alebo aspoň module_id. Inak si jednotlivé inštancie môžu navzájom prepisovať cache.

Po správnom doplnení file cache sa databázovo náročný výpočet vykoná len pri prvom načítaní alebo po invalidácii. Ostatní návštevníci potom dostanú rýchlo pripravené dáta zo súboru v system/storage/cache/.