Met de komst van Magento 2 zijn er een hoop nieuwe functionaliteiten geïntroduceerd om het leven van de Magento developer gemakkelijker te maken. Plugins zijn functies die gebruikt kunnen worden zonder dat de standaard functie volledig overschreven hoeft te worden – wat in Magento 1 dagelijkse kost was.

Het grote nadeel van deze rewrites binnen Magento 1 is het stoeien met meerdere rewrites voor een en dezelfde functie, wat weer voor conflicten tussen maatwerk extensies zorgde. Binnen Magento 2 zijn er hiervoor andere mogelijkheden gekomen in de vorm van class preferences en argument replacement) – maar wat de kroon echt spant zijn de Magento 2 plugins. De voordelen zijn:

  1. Luisteren naar een public function (behalve public functions waarin ‘final’ vernoemd staat) die opgeroepen wordt door de object manager;
  2. Het wijzigen van de return value van deze functie;
  3. Het wijzigen van de argumenten binnen deze functie;
  4. Dit alles op zo’n manier zodat andere modules ook de mogelijkheid behouden om op deze functie in te haken door volgorden aan te geven.

De Magento 2 plugins komen in drie smaakjes: before, around en after. Zoals de namen al zeggen komen deze voor, na of om de functie heen waarop een plugin geschreven wordt. Door middel van het interceptor pattern wat Magento 2 gebruikt kan er data van of naar deze functies gewijzigd worden. Voor iedere plugin wordt er automatisch een Interceptor klasse aangemaakt en in de generation map gezet. Binnen deze Interceptor klasse is te zien dat deze extend van de klasse waarop de plugin geschreven is. Wat erg relaxed aan deze plugins is: je hoeft hier niet over na te denken. Het is ‘slechts’ een klasse die tussen de developer en de klasse waarop de plugin gebouwd is zit.

Plugins worden in eerste instantie gedefinieerd in de di.xml. Door aan te geven om welk type het gaat en daarbinnen de plugin te definiëren wordt de generation klasse automatisch aangemaakt. Zie onderstaand voorbeeld:

<type name="Guapa\Extension\Block\Hola">
 <plugin name="hola_before_plugin"
 type="Guapa\Extension\Block\Plugin\HolaPlugin"
 sortOrder="1"
 />
</type>

Voor de Guapa\Extension\Block\Hola klasse wordt de plugin geschreven. De (public) functies binnen deze klasse worden zo beschikbaar gesteld om een before, around of after functie te krijgen. De plugin zelf krijgt een unieke naam – de type definieert waarin de plugin functies gevonden kunnen worden. Last but not least: met de sortOrder geef je volgordes aan, wanneer er bijvoorbeeld meerdere plugins voor de zelfde klasse geschreven zijn.

/**
 * Class Hola
 * @package Guapa\Extension\Block
 */
class Hola extends Template
{
 const GREETING = 'Hola!';

 /**
 * @param $argument
 * @return array
 */
 public function guapa($argument)
 {
 return [
 __METHOD__,
 $argument
 ];
 }
}

Binnen bovenstaande klasse Hola – waarbij de ‘guapa’ functie aangepast dient te worden – is onderstaande before plugin geschreven. Door ‘before’, ‘around’ of ‘after’ voor de te gebruiken functie te zetten en de plugin te vertellen wat $subject is (de klasse waarvoor de plugin geschreven is) is een werkende plugin een feit.

/**
 * @param Hola $subject
 * @param $argument
 * @return array
 */
public function beforeGuapa(
 Hola $subject, $argument
) {
 echo __METHOD__;
 $argument = (!$argument)
 ? $subject::GREETING
 : $argument;
 return [$argument];
}

In bovenstaand voorbeeld is te zien dat $argument in de before plugin gevuld wordt met data vanuit de Hola klasse. Met een plugin kun je functies (en andere public data) van de klasse waarop de plugin geschreven is dus gewoon benaderen via $subject. De ‘guapa’ functie (met een leeg argument) geeft nu het volgende terug:

Guapa\Extension\Block\Plugin\HolaPlugin::beforeGuapa
Guapa\Extension\Block\Hola::guapa
Hola Guapa!

In bovenstaand resultaat is te zien dat de before plugin inderdaad als eerste kwam – pas daarna werd de originele functie getriggerd. Een after plugin werkt in principe hetzelfde. In de laatst genoemde plugin geef je geen $argument meer mee maar krijg je een $returnValue terug (de normale functie is immers al uitgevoerd), zie onderstaand voorbeeld:

/**
 * @param Hola $subject
 * @param $returnValue
 * @return array
 */
public function afterGuapa(
 Hola $subject, $returnValue
) {
 $returnValue[] = __METHOD__;
 return $returnValue;
}

In bovenstaand voorbeeld wordt het resultaat van de ‘guapa’ functie nog aangepast en vervolgens weer terug gegeven. Dit geeft het volgende resultaat:

Guapa\Extension\Block\Hola::guapa
Guapa\Extension\Block\Plugin\HolaPlugin::afterGuapa

Met een around plugin heb je toegang tot zowel de functionaliteiten van een before als after plugin. Ook heb je de mogelijkheid de normale functie compleet over te slaan. Zie onderstaand voorbeeld:

/**
 * @param Hola $subject
 * @param callable $proceed
 * @param $argument
 */
public function aroundGuapa(
 Hola $subject, callable $proceed, $argument
) {
 echo __METHOD__ . ' --before';
 $argument = (!$argument)
 ? $subject::GREETING
 : $argument;
 var_dump($proceed($argument));
 echo __METHOD__ . ' --after';
}

Deze around plugin geeft onderstaand resultaat. Te zien is dat zowel het fijne van de before als het goede van de after te gebruiken is. Door $proceed niet aan te roepen is het mogelijk de originele functie compleet over te slaan.

Guapa\Extension\Block\Plugin\HolaPlugin::aroundGuapa --before
Guapa\Extension\Block\Hola::guapa
'Hola Guapa!
Guapa\Extension\Block\Plugin\HolaPlugin::aroundGuapa --after

De mogelijkheden wat betreft plugins dus groot. Dit zijn slechts tekstuele voorbeelden, maar denk eens aan de mogelijkheden betreft het aanpassen van collecties, template functionaliteiten en het toevoegen van andere klasses die gebruikt kunnen worden via het gebruik van dependancy injection.. Dat klinkt wat mij betreft als een uitstekende verbetering op de beperkte mogelijkheden in Magento 1. Meer weten? Plan een Magento 2 demo met onze experts in