Design Pattern Plugins

Um plugin, ou interceptor, é uma classe que modifica o comportamento de funções de classe pública interceptando uma chamada de função e um código em execução antes, depois ou ao redor a execução. Isso permite que você substitua ou estenda o comportamento de métodos públicos originais para qualquer classe ou interface.

Extensões que desejam interceptar e alterar o comportamento de um método público podem criar uma classe Plugin.

Essa abordagem de interceptação reduz conflitos entre extensões que alteram o comportamento da mesma classe ou método. Sua implementação de classe altera o comportamento de uma função de classe, mas não altera a classe em si. O Magento chama esses interceptadores seqüencialmente de acordo com uma ordem de classificação configurada, para que eles não entrem em conflito um com o outro.

Limitações

Plugins não podem ser usados ​​nos seguintes casos:

  • Métodos finais
  • Classes finais
  • Métodos não públicos
  • Métodos de classe (como métodos estáticos)
  • __construct
  • Tipos virtuais
  • Objetos que são instanciados antes Magento\Framework\Interception são inicializados

Declarando um plugin

Fazemos a declaração do plugin no arquivo di.xml do módulo:

<config>
    <type name="{ObservedType}">
      <plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false" />
    </type>
</config>

Obrigatórios

  • type name –> Uma classe ou interface que o plug-in observa
  • plugin name –> Nome que identifica o plugin. Também é usado para mesclar as configurações do plug-in.
  • plugin type –> O nome da classe de um plugin ou seu tipo virtual.

Opcionais

  • plugin sorterOrder –> Plugins que chamam o mesmo método os executam usando este pedido.
  • plugin disabled –> Para desabilitar um plug-in, defina esse elemento como true. O valor padrão é false.

Definindo um plugin

Ao aplicar código antes, depois ou em torno de um método público, um plug-in estende ou modifica o comportamento desse método.

O primeiro argumento para os métodos antes, depois e ao redor é um objeto que fornece acesso a todos os métodos públicos da classe do método observado.

Before (Antes)

O Magento executa todos os métodos antes da chamada para um método observado. Esses métodos devem ter o mesmo nome do método observado com before como o prefixo.

Você pode usar antes de métodos para alterar os argumentos de um método observado retornando um argumento modificado. Se houver mais de um argumento, o método deve retornar uma matriz desses argumentos. Se o método não alterar o argumento do método observado, ele deverá retornar null.

<?php
namespace My\Module\Plugin;

class ProductAttributesUpdater
{
    public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)
    {
        return ['(' . $name . ')'];
    }
}

After (Depois)

O Magento executa todos os métodos após a conclusão do método observado. O Magento exige que esses métodos tenham um valor de retorno e eles devem ter o mesmo nome que o método observado com after como prefixo.

Você pode usar esses métodos para alterar o resultado de um método observado, modificando o resultado original e retornando-o ao final do método.

<?php
namespace My\Module\Plugin;

class ProductAttributesUpdater
{
    public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
    {
        return '|' . $result . '|';
    }
}

Com o uso do after temos acesso a todos os argumentos de seus métodos observados. Quando o método observado é concluído, o Magento passa o resultado e os argumentos para o próximo método. Se o método observado não retornar um resultado ( @return void), ele passará nullpara o próximo método.

Abaixo está um exemplo de um método after que aceita o resultado null e os argumentos do método do login observado para Magento\Backend\Model\Auth

<?php
namespace My\Module\Plugin;

class AuthLogger
{
    private $logger;

    public function __construct(\Psr\Log\LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @param \Magento\Backend\Model\Auth $authModel
     * @param null $result
     * @param string $username
     * @return void
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterLogin(\Magento\Backend\Model\Auth $authModel, $result, $username)
    {
        $this->logger->debug('User ' . $username . ' signed in.');
    }
}

Com o uso do after não precisamos declarar todos os argumentos de seus métodos observados, exceto aqueles que o método usa e quaisquer argumentos do método observado que vêm antes daqueles argumentos usados.

O exemplo a seguir é uma classe com um método after para \Magento\Catalog\Model\Product\Action::updateWebsites($productIds, $websiteIds, $type):

class WebsitesLogger
{
    private $logger;

    public function __construct(\Psr\Log\LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function afterUpdateWebsites(\Magento\Catalog\Model\Product\Action $subject, $result, $productIds, $websiteIds)
    {
        $this->logger->log('Updated websites: ' . implode(', ',  $websiteIds));
    }
}

Around (Ao redor)

O Magento executa o código ao redor de métodos antes e depois de seus métodos observados. Usando esses métodos, você pode substituir um método observado. Em torno de métodos deve ter o mesmo nome que o método observado com around como o prefixo.

<?php
namespace My\Module\Plugin;

class ProductAttributesUpdater
{
    public function aroundSave(\Magento\Catalog\Model\Product $subject, callable $proceed)
    {
        $someValue = $this->doSmthBeforeProductIsSaved();
        $returnValue = null;
        
        if ($this->canCallProceedCallable($someValue)) {
            $returnValue = $proceed();
        }
        
        if ($returnValue) {
            $this->postProductToFacebook();
        }
        
        return $returnValue;
    }
}

Quando você envolve um método que aceita argumentos, seu plugin também deve aceitar esses argumentos e você deve encaminhá-los quando invocar o proceedcallable. Você deve ter cuidado para corresponder aos parâmetros padrão e digitar dicas da assinatura original do método.

Por exemplo, o código a seguir define um parâmetro do tipo SomeTypeque é nulo:

<?php
namespace My\Module\Model;

class MyUtility
{
    public function save(SomeType $obj = null)
    {
        //do something
    }
}

Você deve envolver este método com um plugin como abaixo:

<?php
namespace My\Module\Plugin;

class MyUtilityUpdater
{
    public function aroundSave(\My\Module\Model\MyUtility $subject, callable $proceed, SomeType $obj = null)
    {
      //do something
    }
}

Se você esquecer do = nulle o Magento chamar o método original null, o PHP lançará um erro fatal, pois seu plugin não aceita null.

Para mais informações, Plugins Interceptors.

Dúvidas? Posta aí!!!

Um abraço.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *