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

Jak zrychlit modul pro internetový obchod OpenCart

Možná jste instalovali modul pro OpenCart 3 a po jeho zapnutí se stránka, kde se modul vykresluje, výrazně zpomalila. Častou příčinou bývá to, že modul při každém načtení znovu skládá stejná data z databáze. Řešením bývá doplnění datové cache do system/storage/cache/.

Tento návod popisuje obecný a bezpečný postup pro moduly třetích stran v OpenCart 3. Je zaměřený na situaci, kdy modul na frontendu generuje stejný výstup opakovaně a jeho výpočet je zbytečně drahý.

Jak funguje file cache v OpenCartu 3

OpenCart má vestavěnou třídu Cache. Pokud je použit adaptér file, ukládají se data do souborů ve složce system/storage/cache/.

Průběh je obvykle tento:

  • První požadavek: Modul spočítá data, uloží je do cache a vrátí výstup.
  • Další požadavky: Modul se nejdřív pokusí načíst data z cache. Pokud existují, neprovádí znovu těžké SQL dotazy ani další náročnou logiku.
  • Expirace: U file cache v OpenCartu není potřeba ukládat vlastní timestamp do dat. Expirace je součástí názvu cache souboru a řeší ji samotná knihovna cache.
  • Invalidace: Když se změní nastavení modulu nebo zdrojová data, je potřeba příslušnou cache smazat metodou $this->cache->delete(...).

Kdy se tento postup hodí

Typicky tehdy, když modul na frontendu opakovaně:

  • načítá kategorie, produkty nebo jiné seznamy z databáze,
  • sestavuje složitá vícerozměrná pole, HTML bloky nebo stromové struktury,
  • volá více modelů uvnitř několika vnořených cyklů,
  • vrací stejný výsledek pro mnoho návštěvníků.

Naopak opatrnost je potřeba u modulů, jejichž výstup závisí na konkrétním zákazníkovi, košíku, přihlášení, měně, aktivní kategorii, jazyku nebo jiném kontextu. V takovém případě musí být tyto hodnoty součástí cache klíče, nebo se daná část nesmí cachovat vůbec.

Krok 1: Najděte část frontend controlleru, která server nejvíce zatěžuje

Otevřete controller modulu, nejčastěji v cestě catalog/controller/extension/module/[nazev_modulu].php.

Obvykle hledáte metodu index($setting) nebo podobnou hlavní metodu. Cílem je obalit cache pouze tu část, která připravuje datové pole pro šablonu. Běžné načtení jazyka, připojení JS/CSS nebo jiné lehké operace mohou zůstat mimo cache.

Krok 2: Sestavte správný cache klíč

Klíč musí rozlišit všechny stavy, ve kterých může mít modul jiný výstup. Nestačí jen název modulu. Často je potřeba zahrnout například:

  • nastavení konkrétní instance modulu v parametru $setting,
  • store_id, pokud máte více obchodů,
  • language_id, pokud modul vypisuje překlady nebo lokalizovaná data,
  • customer_group_id, pokud se liší ceny nebo viditelnost produktů,
  • theme, pokud se datová struktura liší podle šablony,
  • path, product_id, manufacturer_id nebo jiný parametr URL, pokud se podle něj mění aktivní položky nebo obsah modulu.

Bezpečný obecný vzor:

$cache_key = 'module_[nazev_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'] : ''
)));

Pokud výstup na path nebo jiné URL proměnné nezávisí, do klíče je nedávejte. Zbytečně byste si rozdrobili cache do mnoha souborů.

Krok 3: Nejdříve zkuste načíst data z cache

Na začátek náročné části vložte kontrolu cache. Pokud data existují, rovnou je použijte.

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

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

Tady je důležité, že ukládáte přímo finální datové pole pro šablonu, typicky proměnnou $data. OpenCart file cache už sama řeší životnost souboru, takže není potřeba do cache ukládat další pole typu expire nebo ttl.

Krok 4: Ponechte původní logiku modulu a uložte výsledná data

Původní náročný kód zůstane prakticky beze změny. Jen po jeho dokončení uložíte finální data do cache.

// Pokud cache neexistuje, proběhne původní logika modulu:
// - načtení kategorií
// - načtení produktů
// - skládání stromu
// - příprava pole $data pro twig

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

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

Tím dosáhnete toho, že první návštěvník výstup spočítá a další už dostanou hotová data z cache souboru.

Krok 5: Invalidace cache po změně nastavení modulu

Otevřete administrátorský controller modulu, obvykle admin/controller/extension/module/[nazev_modulu].php.

Po uložení nastavení vložte smazání cache. Doporučený postup je mazat společný prefix, ne konkrétní hash.

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

U file cache v OpenCartu se tím smažou všechny soubory začínající na tomto prefixu, například cache.module_[nazev_modulu].abc123.... To je důležité, protože jednotlivé varianty modulu bývají rozlišeny hashí podle jazyka, obchodu, nastavení nebo URL kontextu.

Krok 6: Invalidace i při změně zdrojových dat

Samotné uložení nastavení modulu často nestačí. Pokud modul zobrazuje produkty, kategorie, výrobce, recenze nebo jiná data z administrace, je vhodné mazat cache i při změně těchto dat.

Příklady:

  • modul pracující s produkty: mazat cache po uložení nebo smazání produktu,
  • modul pracující s kategoriemi: mazat cache po změně kategorie,
  • modul se značkami nebo blogem: mazat cache při úpravě odpovídajících záznamů.

Jinak se může stát, že modul zůstane funkční a rychlý, ale bude po určitou dobu zobrazovat zastaralá data až do expirace cache.

Krok 7: Jak dlouho cache žije

Ve standardním OpenCart 3 je u file cache běžná životnost často 3600 sekund, tedy 1 hodina. Tato hodnota se předává při vytvoření instance cache a file adaptor ji zapisuje do názvu souboru.

Praktický důsledek:

  • po uplynutí času se cache soubor považuje za expirovaný,
  • staré soubory se průběžně mažou při práci s cache,
  • není potřeba vlastní ruční práce s timestampem uvnitř uložených dat.

Krok 8: Jak cache ručně vyčistit při testování

Při ladění nebo testování můžete cache odstranit i ručně ve složce system/storage/cache/.

  • Ruční smazání konkrétní skupiny: smažte soubory začínající na cache.module_[nazev_modulu].
  • Smazání po uložení v administraci: pokud jste správně doplnili $this->cache->delete(...), cache se smaže sama při uložení modulu
  • Automatická expirace: pokud nic nemažete, stará cache sama přestane platit po uplynutí nastavené doby

Poznámka: v některých instalacích OpenCartu tlačítka pro vyčištění vývojářských cache řeší hlavně Twig, SASS nebo modification cache. Datovou file cache modulu je jistější mazat přímo přes $this->cache->delete(...) nebo ručně ve složce system/storage/cache/.

Nejčastější chyby

  • Příliš obecný cache klíč: modul pak vrací špatný obsah pro jiný jazyk, jiný obchod nebo jinou stránku.
  • Příliš detailní cache klíč: cache se zbytečně tříští a přínos se snižuje.
  • Chybějící invalidace: modul je rychlý, ale po úpravách v administraci ukazuje stará data.
  • Cachování per-customer výstupu: může dojít ke zobrazení nesprávných dat jinému zákazníkovi.
  • Cachování příliš brzy: pokud do cache uložíte nedokončená data nebo výstup závislý na další logice, může být výsledek nekonzistentní.

Doporučený obecný vzor

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

    $cache_key = 'module_[nazev_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/[nazev_modulu]', $cache_data);
    }

    $data = array();

    /* === ZDE ZAČÍNÁ PŮVODNÍ NÁROČNÁ LOGIKA MODULU === */
    /* načtení modelů, SQL dotazy, cykly, skládání výstupních dat */
    /* === ZDE KONČÍ PŮVODNÍ NÁROČNÁ LOGIKA MODULU === */

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

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

Praktická poznámka k modulu s více instancemi

Pokud se stejný modul používá na více layoutech nebo ve více instancích, je velmi důležité, aby byl součástí klíče i obsah $setting nebo alespoň module_id. Jinak si jednotlivé instance mohou přepisovat navzájem cache.

Po správném doplnění file cache se databázově náročný výpočet provede jen při prvním načtení nebo po invalidaci. Ostatní návštěvníci pak dostanou rychle připravená data ze souboru v system/storage/cache/.