Search code examples
phpmagento-1.9

Magento 1 - Dispatch custom event for all methods that extends a parent method


I'm developing a Magento 1 module that will be extended by other modules. Here I will call the parent module as parent and the "child" module (the module that will extend the classes from parent) as child.

I have an abstract class declared for the parent that has an abstract method called loadExternalItem. This method loads an external item (like a product) from an external source. For the child module in this case, that external source is an ERP API that is called in this method to retrieve a product:

<?php

class Child_Module_Model_Entity_Product extends Parent_Module_Model_Entity_Abstract
{
    /** Inherited from Parent_Module_Model_Entity_Abstract */
    public function loadExternalItem($item)
    {
        $query = array("query_parameters" => array("id" => $item->getId()));
        $response = Mage::getModel("child/api_request")
            ->make("GET", "PRODUCT_BY_ID", $query);

        return $response->getItemFromResponse();
    }
}

My question is: where (in the parent module) shoud I dispatch my event (say my_custom_event) in a way that all modules that extends loadExternalItem run it without specifying it in the inherited method's body?

Anyway to do that with abstract methods? Only way I can think is to not declare the method as abstract and call the dispatch event in the body of the parent method:

<?php

class Parent_Module_Model_Entity_Abstract extends Mage_Core_Model_Abstract
{
    public function loadExternalItem($item)
    {
        Mage::dispatchEvent("my_custom_event");
    }
}

And call it at the end of the child's method:

<?php

class Child_Module_Model_Entity_Product extends Parent_Module_Model_Entity_Abstract
{
    /** Inherited from Parent_Module_Model_Entity_Abstract */
    public function loadExternalItem($item)
    {
        $query = array("query_parameters" => array("id" => $item->getId()));
        $response = Mage::getModel("child/api_request")
            ->make("GET", "PRODUCT_BY_ID", $query);

        $responseItem = $response->getItemFromResponse();
        parent::importExternalItem($item); /** Calls the dispatch event */
        return $responseItem;
    }
}

But it seems "hacky" and not so efficient, because the main reason is to avoid that developers working in a new child module forget to dispatch this event, and in this case they might as well forget to call the parent::importExternalItem().


Solution

  • The standard way to do parent-child inherited method is like this:

    Parent:

    <?php
    
    abstract class Parent_Module_Model_Entity_Abstract extends Mage_Core_Model_Abstract
    {
        /** 
         * @param Some_Item $item
         * @return $this
         */
        protected function _loadExternalItem($item)
        {
            return $this;
        }
    
        /** 
         * @param Some_Item $item
         * @return $this
         */
        public function loadExternalItem($item)
        {
            // Mage::dispatchEvent("parent_entity_load_external_item_before", ['some_item' => $item]);
            $this->_loadExternalItem($item);
            Mage::dispatchEvent("parent_entity_load_external_item_after", ['some_item' => $item]);
            return $this;
        }
    }
    

    Child:

    <?php
    
    class Child_Module_Model_Entity_Product extends Parent_Module_Model_Entity_Abstract
    {
        /** 
         * @inheritdoc
         */
        protected function _loadExternalItem($item)
        {
            $query = array("query_parameters" => array("id" => $item->getId()));
            $response = Mage::getSingleton("child/api_request")
                ->make("GET", "PRODUCT_BY_ID", $query);
    
            $responseItem = $response->getItemFromResponse();
            $this->setExternalItem($responseItem); // magic setter-getter
            
            return parent::_loadExternalItem($item);
        }
    }
    

    To call:

    $item = Mage::getModel('child/product')
        ->load(123)
        ->loadExternalItem($item)
        ->getExternalItem();