Ako som riešil preusporiadanie atribútov v Magento?

Pred niekoľkými týždňami som z nášho interného ecommerce tímu prešiel do novej zmiešanej zostavy kolegov. Pracujem v kooperácii s interným IT tímom spoločnosti United Fashion Group (UFG) a ďalšou externou IT spoločnosťou, ktorá pre klienta pracuje tiež. Spoločne vylepšujeme 7 eshopov (v rôznych jazykových mutáciách) spravovaných z jednej administrácie. Čoskoro k nim navyše pribudne ďalší. Celé to beží na Magente, ktoré je pre mňa novou výzvou. 

Magento je ecommerce platforma, ktorá umožňuje spravovať viacero online obchodov z jedného miesta. Ide o robustné, ale hlavne dobre prispôsobiteľné riešenie, ktoré sa dá upravovať podľa požiadaviek a potrieb klienta. Je preto vhodné hlavne pre rozrastajúce sa alebo veľké podniky. Umožňuje spravovať celý životný cyklus produktu (vytvorenie, naskladnenie, predaj…) ale napríklad aj menšie funkcie, ako optimalizáciu pre vyhľadávače.

V čase písania tohto článku (Október 2022) sa na Marketplace nachádza viac ako 3300 pluginov do rozšírení Magento. Je potrebné spomenúť, že niektoré rozšírenia sú zadarmo, ale za iné je potrebné si priplatiť. Najviac je rozšírení týkajúcich sa Obsahu a Prispôsobenia, zabezpečujúcich napríklad Vrstvenú navigáciu, ktorá nám umožňuje zvolenie viacerých atribútov produktu súčasne v rámci filtrovania produktov v katalógu.

Niekedy treba aj plugin

Moje prvé úlohy na tejto platforme boli “oťukávačky” – úprava zaokrúhľovania, pridávanie nového filtra do administrácie alebo preusporiadanie atribútov (atribútypredstavujú informácie, respektíve vlastnosti objektov, akými sú napríklad produkty – medzi atribúty produktov, môžeme zaradiť napríklad cenu, výrobcu, alebo farbu a mnohé ďalšie).

Niektoré úlohy bolo potrebné riešiť s využitím pluginov a preto si teraz o nich niečo v krátkosti povieme. V prípade úlohy úpravy usporiadania atribútov boli pluginy použité preto, lebo hlavná funkcionalita sa nachádza v jadre Magenta (pod slovným spojením jadro Magenta je v tomto prípade myslené celé Magento, ktoré je nainštalované vo /vendor adresári, kde sa nerobia žiadne zmeny v kóde), alebo v príslušných moduloch, a teda nebolo možné vykonať potrebné zmeny priamo v daných metódach.

Typy a prefixy

S využitím pluginov je možné ovplyvniť správanie požadovaných metód v rámci konkrétneho modulu a pre potrebný scope (admin/frontend/…). Je to možné docieliť úpravou vstupných/výstupných parametrov alebo obalením metódy do akejsi “bubliny”, v ktorej sa bude táto metóda vykonávať spolu s príslušnými zmenami. Metóda, ktorá je takýmto spôsobom modifikovaná sa nazýva pozorovaná metóda.

Existujú tri typy pluginov, akými sú (poznámka autora: dáme si to bez prekladu ? ):

  • Before methods – vykonávajú sa pred spustením pozorovanej metódy. Slúžia na modifikovanie vstupných argumentov pozorovanej metódy.
  • After methods – vykonávajú sa po ukončení vykonávania pozorovanej metódy. Slúžia na modifikovanie výsledku pozorovanej metódy.
  • Around methods – vykonávajú sa pred spustením a po ukončení vykonávania pozorovanej metódy. Slúžia na prepísanie (modifikovanie vstupov a výsledku) pozorovanej metódy. Neodporúča sa ich používať pretože negatívne ovplyvňujú výkon.

Dôležitú úlohu pri vytváraní pluginov zohráva prefix v rámci názvu novej metódy, ktorá bude modifikovať pozorovanú metódu. Tento prefix závisí na type pluginu, aký chceme vytvoriť. Pri vytváraní before pluginu, musí byť prefix novej metódy ‘before’. Pre before plugin pre pozorovanú metódu foo() by sme vytvorili metódu s názvom beforeFoo(). Toto pravidlo sa analogicky aplikuje pre after a around pluginy.

Ukážka zadania a riešenia pre úlohu preusporiadania atribútov:

V rámci produktového katalógu je v administrácii pri hromadnej akcii update attributes potrebné zmeniť poradie zobrazovaných (získaných) atribútov. K dispozícii je aj zoznam prvých 15 zoradených atribútov, pričom na poradí ostatných atribútov nezáleží.

Atribúty sú zobrazované v poradí v akom sú získané. Na základe zadania je teda potrebné vytvoriť funkcionalitu, ktorá zabezpečí, že výsledne atribúty budú vždy pri ich získavaní zoradené podľa požiadaviek. Preto vytvoríme after plugin.

V rámci riešenia je potrebné zadeklarovať nový plugin pre príslušný modul. V tomto prípade je definovaný plugin pre triedu Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab\Attributes, s názvom Custom_Catalog::afterGetAttributes, ktorého funkcionalita je v rámci triedy Custom\Catalog\Plugin\RearrangeAttributesPlugin.

<type name="Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab\Attributes">
 <plugin name="Custom_Catalog::afterGetAttributes" 
 type="Custom\Catalog\Plugin\RearrangeAttributesPlugin"/>
 </type>

V rámci tejto triedy je funkcionalita zabezpečujúca zoraďovanie atribútov podľa požiadaviek zadania.

<?php
namespace Custom\Catalog\Plugin;
use Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab\Attributes;
use Magento\Framework\DataObject;
class RearrangeAttributesPlugin
{
    /**
     * @var string
     */
    private const REARRANGE_ATTRIBUTE_KEY = 'attribute_code';

Táto hodnota predstavuje kľúč, pod ktorým chceme, aby sa nachádzali jednotlivé atribúty v poli. Každý atribút má pritom unikátnu hodnotu, ktorá je uložená pod týmto kľúčom.

    /**
     * @var string
     */
    private const REARRANGE_ATTRIBUTE_ID = 'attribute_id';

Táto hodnota predstavuje v poli atribútov pôvodný kľúč, pod ktorým sú uložené jednotlivé atribúty. Konkrétne sa jedna o ich unikátny identifikátor.

    /**
     * @var string[]
     */
    private $rearrangeAttributeKeys = [
        'price',
        'config_price',
        'special_price',
        'special_from_date',
        'special_to_date',
        'cost',
        'update_on_observer',
        'season_report',
        'manufacturer',
        'color_filter',
        'news_from_date',
        'news_to_date',
        'material_description',
        'product_tag',
        'category_report',
    ];

Toto pole obsahuje prvých pätnásť kódov atribútov. Pričom tieto hodnoty sa nachádzajú pod kľúčom ‘attribute_code’ v poli atribútov.

    /**
     * @param Attributes $subject
     * @param DataObject[] $result
     *
     * @return DataObject[]
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterGetAttributes(Attributes $subject, array $result): array

Funkcia zabezpečujúca správne zoradenie atribútov.

    {
        $rearrangeAttributes = [];
        foreach ($result as $key => $attribute) {
            $result[$attribute->getData(self::REARRANGE_ATTRIBUTE_KEY)] = $attribute;
            unset($result[$key]);
        }

Prvý cyklus vymení kľúče. Nový kľúč pod ktorým bude uložený atribút je jeho ‘attribute_code’

        foreach ($this->rearrangeAttributeKeys as $attributeKey) {
            if (isset($result[$attributeKey])) {
                $rearrangeAttributes[] = $result[$attributeKey];
                unset($result[$attributeKey]);
            }
        }

Druhý cyklus sa postará o vyfiltrovanie požadovaných atribútov. Tým že sú teraz atribúty uložené pod iným kľúčom, je zabezpečený rýchly prístup k danému atribútu. Následne nájdený prvok odstránime z poľa. Na konci cyklu budeme mať k dispozícii pole usporiadaných atribútov a pole zvyšných neusporiadaných atribútov.

        $result = array_merge($rearrangeAttributes, $result);

Teraz spojíme tieto dve polia do jedného. Na jeho začiatku sa budú nachádzať usporiadané atribúty a za nimi zvyšné neusporiadané atribúty.

        $output = [];
        foreach ($result as $attribute) {
            $output[$attribute->getData(self::REARRANGE_ATTRIBUTE_ID)] = $attribute;
        }

Posledný cyklus sa postará o nastavenie kľúčov. Kľúč pod akým budú teraz uložené atribúty v poli, bude ich pôvodný kľúč, a teda ich ‘attribute_id’.

        return $output;
    }
}

Takéto zadania riešime na dennej báze, samostatne alebo v tíme. Aktuálne sa venujem najmä príprave nového eshopu, ktorý k ostatným obchodom UFG čoskoro pripojíme. Keďže ide o rozsiahly projekt, každá nová funkcionalita ovplyvňuje všetko ostatné a preto je veľmi dôležitý dôkladný testing.

Na druhej strane výhodou veľkého projektu je väčší priestor na optimalizácie a code reviews. Na Magente je navyše skvelé to, že ide o celosvetovo známu open-source platformu, preto je pri každom probléme možné poradiť sa s obrovskou online komunitou. Navyše mám stále po ruke aj kolegov, ktorí mi radi pomôžu.