Criando um Evento Personalizado no Magento: Primeiro Pedido do Cliente

Eventualmente você se deparará com um ou outro caso nos quais faltam alguns eventos no Magento que você poderia facilmente capturar em um observer. Em vários casos podemos criar novas funcionalidades que possam nos ajudar a desenvolver algo melhor e com mais solidez, pois o Magento lhe permite isso. Para nossa sorte, fazer o Magento dar um dispatch de um novo evento personalizado é uma tarefa bem simples.

Imagine um caso em que seu cliente vira para você e diz: preciso dar pontos para o Cliente A que Convidar um Cliente B. Estes pontos serão transferidos para o Cliente A poder utilizar apenas uma vez e deve ser no momento quando o Cliente B fizer seu primeiro pedido na loja.

Um cenário ideal seria se existisse no Magento um evento como “customer_first_order” ou algo mais preciso levando em consideração o status do pedido, por exemplo para pedidos completos “customer_first_order_that_reached_state_complete”. Pensando na possibilidade de clientes como o citado acima pedirem este tipo de coisa, vou lhe mostrar como criar eventos personalizados no Magento e você verá que não se trata de um martírio com centenas de linhas de programação.

Então, por onde começamos? Eu começarei por evento do Core do Magento “sales_order_save_after”. Logicamente, eu preciso fazer algo após o pedido ser criado. A partir deste evento eu criarei um pouco de lógica para avaliar se realmente é o primeiro pedido do cliente ou não. Caso você seja novato em Magento e, no momento em que leu isso, fizer uma busca dentro de todos os arquivos da instalação do Magento por Mage::dispatchEvent(‘sales_order_save_after’, array(‘object’=>$this)); já vou lhe avisando que você não encontrará este evento em lugar algum.

Entretanto você encontrará valores definidos para as variáveis $_eventPrefix e $_eventObject dentro da classe Mage_Sales_Model_Order.
Uma vez que Mage_Sales_Model_Order extende a classe Mage_Core_Model_Abstract ela herda o método _afterSave(), entre outros, possibilitando assim que exista um dispatch adicional quando um objeto da classe sales_order_save_after é salvo. o método _afterSave() dispara o evento da seguinte forma: Mage::dispatchEvent($this->_eventPrefix.’_save_after’, $this->_getEventData());.

A coisa mais importante para nós é “capturar” os parâmetros que são passados para o evento. A função $this->_getEventData()) basicamente retorna array(‘data_object’ => $this, $this->_eventObject => $this);. Como mencionei anteriorment a variável $_eventObject contém em seu valor um objeto “order” pertecente a classe Mage_Sales_Model_Order. O que significa que tudo o que precisamos fazer em nosso observer que captura o evento “sales_order_save_after” é obter este objeto order passado no evento da seguinte forma: $observer->getEvent()->Order();.

A partir daí, podemos começar a implementar o código para a necessidade específica de nosso cliente. Antes de começarmos, aqui está o código necessário para capturar o evento sales_order_save_after e poder implementar a lógica dentro de algum método em algum observer.

O arquivo config.xml do seu módulo:

<config>
//...
    <frontend>
        <events>
            <sales_order_save_after>
                <observers>
                    <customer_first_order>
                        <class>myClassGroup/observer</class>
                        <method>handleCustomerFirstOrder</method>
                    </customer_first_order>
                </observers>
            </sales_order_save_after>
        </events>
    </frontend>
//...
</config>

O arquivo Observer.php do seu módulo:

class MyCompany_MyExtension_Model_Observer
{
    public function handleCustomerFirstOrder(Varien_Event_Observer $observer)
    {
    }
}

Agora precisamos adicionar uma logica necessária que implementará a necessidade específica do cliente, o que transformará o arquivo Observer.php acima neste:

class MyCompany_MyExtension_Model_Observer
{
    private static $_handleCustomerFirstOrderCounter = 1;
    public function handleCustomerFirstOrder($observer)
    {
        $orders = Mage::getModel('sales/order')
                    ->getCollection()
                    ->addFieldToSelect('increment_id')
                    ->addFieldToFilter('customer_id', array('eq' => $observer->getEvent()->getOrder()->getCustomerId()));
        //$orders->getSelect()->limit(2);
        //if ($orders->count() == 1) {
        if ($orders->getSize() == 1) {
            if (self::$_handleCustomerFirstOrderCounter > 1) {
                return $this;
            }
            self::$_handleCustomerFirstOrderCounter++;
            Mage::dispatchEvent('customer_first_order', array('order' => $observer->getEvent()->getOrder()));
        }
        return $this;
    }
}

Várias coisas devem ser explicadas aqui.

Primeiro o uso do $_handleCustomerFirstOrderCounter. Notei que durante a mesma página de requisição na action que salva o objeto order, outro possível observer pode salvar o objeto novamente fazendo algumas modificações, etc. Meu código dentro do método handleCustomerFirstOrder($observer) pode ser executado duas ou mais vezes, assim eu utilizei uma variável estática no formato de contador para permitir especificamente a execução apenas uma vez.

Segundo, você notará o limite que eu coloquei na Collection, $orders->getSelect()->limit(2);. A razão para isso é “veja se este é o primeiro pedido do cliente”. Para fazer isso, eu preciso saber se realmente não há outro pedido no sistema para o mesmo cliente. Neste caso não é necessário carregar todos os pedidos gravados para o mesmo cliente, pois se o resultado retornar 2 significa que já não é mais seu primeiro pedido, que é exatamente o que faz o código $orders->count() == 1. Agora você verá que eu comentei as linhas $orders->getSelect()->limit(2); e if ($orders->count() == 1) e utilizei o método getSize(), pois as duas formas são exatamente iguais. A diferença é que o método getSize() vem da classe Varien_Data_Collection_Db e internamente chama o método getSelectCountSql() que especificamente executa contagens na base de dados e é um método mais rápido.

E finalmente, eu poderia implementar minha lógica do ganho de pontos diretamente aí neste método, mas decidi disparar o evento customer_first_order para este caso. A razão é simples, talvez outros desenvolvedores do sistema gostariam de fazer alguma coisa neste evento, então por que não dar um dispatch dele?

Para concluir o pedido do cliente eu simplesmente implementei um ou mais observers que capturam o evento customer_first_order e dentro deste observer eu dou ao cliente da loja os seus pontos tão merecidos.

Espero que este artigo tenha lhe ajudado a entender um pouco mais sobre eventos e observers no Magento.

Até a próxima!

Tiago Sampaio

Leave A Reply

Navigate