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á null
para 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 proceed
callable. 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 SomeType
que é 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 = null
e 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.