-
Uneori trebuie sa suprascriem un observator (observer). Prima metoda care vine in general in minte este suprascrierea modelului. In general se numeste Observer.php, pentru ca aceasta este “best practice”.
Dar NU, nu trebuie suprascris modelul. Oricum Observer.php nu extinde nimic si in general contine toti observatorii pentru modul, deci nu poti suprascrie in mai multe module acelasi observer.
Cum functioneaza?
In magento cand se adauga un nou observer, acesta trebuie sa aiba un identificator unic. Acest identificator este cheia!De fapt, mai este un element: “zona”. Cand se face Mage::dispatchEvent(…) se vor rula evenimentele dupa “zona” si dupa “identificator”.
De exemplu sistemul de notificari din admin, care se leaga de evenimentul “controller_action_predispatch”, va rula:
1=> "global"(zona) 2=> "controller_action_predispatch"(event) 3=> "adminnotification"(identificator)apoi:
1=> "adminhtml"(zona) 2=> "controller_action_predispatch"(event) 3=> "adminnotification"(identificator)Daca era vorba de un event in frontend, ar fi fost: “global” apoi “frontend”.
Suprascrierea
Suprascrierea, de fapt, consta intr-un observer definit in aceeasi zona de config ca evenimentul initial(global, frontend sau adminhtml), atasat la acelasi eveniment si cu acelasi identificator cu cel initial (ex: adminnotification).Sa zicem ca trebuie sa suprascriem “adminnotification”. Acest observer se afla in modulul Mage/AdminNotification. Identificatorul unic este in etc/config.xml:
1... 2 <adminhtml> 3... 4 <events> 5 <controller_action_predispatch> 6 <observers> 7 <adminnotification> 8 <class>adminnotification/observer</class> 9 <method>preDispatch</method> 10 </adminnotification> 11 </observers> 12 </controller_action_predispatch> 13 </events> 14... 15 </adminhtml> 16...Din exemplul de mai sus putem vedea:
– zona: adminhtml
– event: controller_action_predispatch
– identificator: adminnotificationFisierul de activare a modulului va fi: app/etc/modules/CP_AdminNotification.xml
1<?xml version="1.0"?> 2<config> 3 <modules> 4 <CP_AdminNotification> 5 <active>true</active> 6 <codePool>local</codePool> 7 <depends> 8 <Mage_AdminNotification/> 9 </depends> 10 </CP_AdminNotification> 11 </modules> 12</config>Am adaugat si dependinte pentru ca fara acel modul, modulul de fata este iuntil.
Este “best practice” sa denumesti un modul suprascris la fel ca modulul initial.
Fisierul de configurare pentru modul va contine practic tot ce avem nevoie pentru suprascriere: zona, event si identificator. Fisierul se afla in app/code/local/CP/AdminNotification/etc/config.xml:
1<?xml version="1.0"?> 2<config> 3 <modules> 4 <CP_AdminNotification> 5 <version>0.0.1</version> 6 </CP_AdminNotification> 7 </modules> 8 <global> 9 <models> 10 <cp_adminnotification> 11 <class>CP_AdminNotification_Model</class> 12 </cp_adminnotification> 13 </models> 14 </global> 15 <adminhtml> 16 <events> 17 <controller_action_predispatch> 18 <observers> 19 <adminnotification> 20 <class>cp_adminnotification/observer</class> 21 <method>overwrittenPreDispatch</method> 22 </adminnotification> 23 </observers> 24 </controller_action_predispatch> 25 </events> 26 </adminhtml> 27</config>Observerul ar trebui sa contina noua logica. Fisierul este in app/ code/local/CP/AdminNotification/Model/Observer.php, asa cum era si evident, dupa structura de mai sus.
1<?php 2 3class CP_AdminNotification_Model_Observer { 4 5 public function overwrittenPreDispatch(Varien_Event_Observer $observer) { 6 // noua logica din observer 7 } 8}Dezactivarea
Dezactivarea este destul de similara cu suprascrierea, diferenta este in config si faptul ca nu mai este nevoie de un fisier observer, pentru ca nu mai exista o noua logica.Noul fisier de config.xml este:
1<?xml version="1.0"?> 2<config> 3... 4 <adminhtml> 5 <events> 6 <controller_action_predispatch> 7 <observers> 8 <adminnotification> 9 <type>disabled</type> 10 </adminnotification> 11 </observers> 12 </controller_action_predispatch> 13 </events> 14 </adminhtml> 15</config> -
Colectia mea de elePHPanti tocmai s-a dublat, acum sunt 2!
Am vrut si un elePHPant roz sa-i tina companie elePHPantului meu.
Si de data asta tot la eBay am apelat, o cautare scurta a mai gasit un crescator de elePHPanti, de data asta: Herman J. Radtke III. L-am comandat direct de pe site-ul lui de data asta, fara ebay, din simplu motiv ca pe ebay erau calculat gresit transportul.
Chiar si cu transportul corect, elePHPantul cel nou nu a fost tocmai ieftin:
$ RON ElePHPant 16.16 55,51 Transport RO 16.95 58,23 Taxa posta (Vama) 0.6 1.95 Total: 33.71 115,69 O suma nu foarte mica, avand in vedere ca pretul unui elePHPant este de aproximativ 5 euro en-goss.
Acum am format o familie de elePHPanti fericita!
-
Acesta nu este un tutorial despre cum se seteaza o regula de tip Shopping Cart Price Rule in Magento, dar despre cum se implementeaza una noua.
Un tip nou de regula in Magento presupune doua lucuri:
– modificarea admin-ului pt a adauga noua regula folosind un observer pentru adminhtml_block_salesrule_actions_prepareform,
– un mod de aplicare pentru noua regula folosind un observer pentru salesrule_validator_process.Sa luam un exemplu. Sa zicem ca exista o regula de tip Shopping Cart Price Rule care ofera discount diferit in functie de numarul de produse din cos. Se va calcula o valoare de incrementare pentru fiecare pas ($step). Primul produs nu va primi nici un discount, al doilea produs va primi un discount de $step, al doilea produs un discount de 2*$step, pana se ajunge la valoarea maxima de discount. Urmatoarele produse vor avea discount maxim. Ex:
Discount Amount = 50
Discount Qty = 5
Step = Discount Amount / Discount Qty = 10Discountul rezultat:
– 0% prod 1
– 10% prod 2
…
– 50% prod 6
– 50% prod 7Primul pas este activarea modulului cu fisierul: app/etc/modules/CP_ProductNrDiscount.xml
1<?xml version="1.0" encoding="UTF-8"?> 2<config> 3 <modules> 4 <CP_ProductNrDiscount> 5 <active>true</active> 6 <codePool>local</codePool> 7 </CP_ProductNrDiscount> 8 </modules> 9</config>Primul observer, adminhtml_block_salesrule_actions_prepareform, trebuie sa fie in config in zona “adminhtml”, pentru ca se va aplica admin-ul. Acest observer are acces la formularul din admin, permitand modificarea acestuia.
Al doilea observer, salesrule_validator_process, poate sa fie in zona de “frontend” sau “global” din config. Daca este in “frontend” se va aplica doar in partea de frontend, daca este in global acesta se va aplica si in backend daca este nevoie. In general global este necesar atunci cand se fac operatiuni pe cart din backend.
1<?xml version="1.0" encoding="UTF-8"?> 2<config> 3 <modules> 4 <CP_ProductNrDiscount> 5 <version>0.0.1</version> 6 </CP_ProductNrDiscount> 7 </modules> 8 <global> 9 <models> 10 <productnrdiscount> 11 <class>CP_ProductNrDiscount_Model</class> 12 </productnrdiscount> 13 </models> 14 <events> 15 <salesrule_validator_process> 16 <observers> 17 <productnrdiscount> 18 <type>model</type> 19 <class>productnrdiscount/observer</class> 20 <method>salesruleValidatorProcess</method> 21 </productnrdiscount> 22 </observers> 23 </salesrule_validator_process> 24 </events> 25 </global> 26 <adminhtml> 27 <events> 28 <adminhtml_block_salesrule_actions_prepareform> 29 <observers> 30 <productnrdiscount> 31 <type>model</type> 32 <class>productnrdiscount/observer</class> 33 <method>adminhtmlBlockSalesruleActionsPrepareform</method> 34 </productnrdiscount> 35 </observers> 36 </adminhtml_block_salesrule_actions_prepareform> 37 </events> 38 </adminhtml> 39</config>Al doilea observer trebuie sa fie atasat la “frontend” sau “global”, daca trebuie sa ruleze doar in frontend sau si in backend.
Asa cum se poate vedea mai sus, trebuie facut un model Observer care sa aiba cele doua metode care modifica admin-ul si aplica discountul.
1<?php 2/** 3 * Number of product discount module 4 * 5 * @author Claudiu Persoiu https://blog.claudiupersoiu.ro 6 */ 7class CP_ProductNrDiscount_Model_Observer { 8 9 // Noul tip de regula 10 const PRODUCT_NR_DISCOUNT = 'product_nr_discount'; 11 12 /** 13 * Adaugare nou tip de regula in meniul de administrare 14 * 15 * @param Varien_Event_Observer $observer 16 */ 17 public function adminhtmlBlockSalesruleActionsPrepareform 18 (Varien_Event_Observer $observer) { 19 // Extragem campul din formular 20 $field = $observer->getForm()->getElement('simple_action'); 21 // Extragem valorile campului 22 $options = $field->getValues(); 23 // Adaugam noua valoare 24 $options[] = array( 25 'value' => self::PRODUCT_NR_DISCOUNT, 26 'label' => 'Product Number Discount' 27 ); 28 // Setare camp 29 $field->setValues($options); 30 } 31 32 /** 33 * Aplicare discount 34 * Discountul se va aplica la minim 2 produse progresiv cate un "step" pentru 35 * fiecare produs, unde un "step" este discountul maxim / numarul de produse 36 * pe care se aplica. 37 * 38 * @param Varien_Event_Observer $observer 39 */ 40 public function salesruleValidatorProcess(Varien_Event_Observer $observer) { 41 42 // $item typeof Mage_Sales_Model_Quote_Item 43 $item = $observer->getEvent()->getItem(); 44 // $rule typeof Mage_SalesRule_Model_Rule 45 $rule = $observer->getEvent()->getRule(); 46 47 // Numarul de produse de acest fel 48 $qty = $item->getQty(); 49 50 // Trebuie verificat ce tip de regula este, pentru a izola tipul 51 // nostu de regula 52 if($rule->getSimpleAction() == self::PRODUCT_NR_DISCOUNT && $qty > 1) { 53 54 // Detalii regula 55 $discountAmount = $rule->getDiscountAmount(); 56 $discountQty = $rule->getDiscountQty(); 57 58 // Step de discount 59 $step = $discountAmount/$discountQty; 60 61 // Calcul discount 62 $discount = 0; 63 for($i = 1; $i < $qty; $i++) { 64 $itemDiscount = $i * $step; 65 // Daca discountul este mai mare decat discountul maxim 66 // atunci se foloseste discount maxim 67 if($itemDiscount > $discountAmount) { 68 $itemDiscount = $discountAmount; 69 } 70 71 $discount += $itemDiscount; 72 } 73 74 // Discountul propriuzis 75 $totalDiscountAmount = ($item->getPrice() * $discount)/100; 76 77 // Discount in procente pentru fiecare quote item 78 $item->setDiscountPercent($discount / $qty); 79 80 // Setare discount efectiv, practic aceasta este valoarea de discount 81 $result = $observer->getResult(); 82 $result->setDiscountAmount($totalDiscountAmount); 83 $result->setBaseDiscountAmount($totalDiscountAmount); 84 85 } 86 } 87 88}Acest observer se va aplica la fiecare request cand exista module in cart pentru care se aplica regula. Daca discountul trebuie sa se aplice doar pentru anumite produse acestea se pot filtra folosind sesiunea de “Conditions” a regulii definite, asa cum este normal.
-
PHP 5.4 a fost lansat!
Chiar daca acuma este yesterday news… literalmente, ieri 1 martie a fost lansat.
Lista de schimbari este disponibila pe php.net.
Ce regret este ca nici in aceasta versiune nu exista scalar type hinting. Singura modificare la type hinting a fost adaugarea cuvantului “callable”, despre care am mai vorbit cand a fost vorba de closures in PHP 5.4.
Un alt lucru interesant este ca de data asta chiar au fost scoase register_globals si magic_quotes_gpc, deci vechile aplicatii de PHP 4 nu mai au posibilitatea de a deveni compatibile cu ajutorul unor setari in php.ini.
De asemenea a fost adaugata functia hex2bin(), evident nu este foarte importanta,dar este interesant ca bin2hex() exista de la PHP 4. 🙂
-
Exista momente cand ai nevoie sa vezi stack trace-ul, sa stii cum ai ajuns pana la un anumit punct. PHP are doua functii native pentru a realiza acest lucru: debug_backtrace() si debug_print_backtrace. Prima intoarce un array iar a doua afisaza stacktrace-ul pe ecran.
Problema in sine este ca acestea trebuie customizate pentru Magento, pentru ca este foarte posibil cand rulezi debug_backtrace() sa ramai fara memorie inainte sa poti trimite rezultatul catre un fisier de log.
Magento are o functie nativa pentru acest lucru: Varien_Debug::backtrace([bool $return = false], [bool $html = true], [bool $withArgs = true]). Pentru a trimite catre log stacktrace-ul se apeleaza pur si siplu:
1Mage::log(Varien_Debug::backtrace(true, false));Aceasta tehnica este foarte utila in momentul in care vrei sa vezi de unde se initializeaza anumite obiecte si ce metode se ruleaza pana in acel moment.
