In Magento 2, leveraging Dependency Injection (DI) and virtualType
allows developers to create dynamic and flexible customizations without altering core functionality. This guide demonstrates how to create a Magento plugin that modifies product behavior based on a custom flag, enablePlugin
, using virtualType
and includes unit tests to validate the functionality.
Note: This approach is primarily theoretical, designed to showcase the flexibility of Magento’s plugin and virtualType
systems. In practical applications, simpler implementations may suffice.
Step 1: Extend the Product Class
Create a custom product class that extends Magento\Catalog\Model\Product
and includes a boolean flag enablePlugin
.
File: app/code/YourVendor/YourModule/Model/CustomProduct.php
namespace YourVendor\YourModule\Model;
use Magento\Catalog\Model\Product;
class CustomProduct extends Product
{
private $enablePlugin = false;
/**
* Set the enablePlugin value.
*
* @param bool $enablePlugin
* @return void
*/
public function setEnablePlugin(bool $enablePlugin): void
{
$this->enablePlugin = $enablePlugin;
}
/**
* Get the enablePlugin value.
*
* @return bool
*/
public function getEnablePlugin(): bool
{
return $this->enablePlugin;
}
}
Step 2: Configure virtualType
in di.xml
Define virtualType
s in the di.xml
configuration to create variations of the CustomProduct
class with different enablePlugin
values.
File: app/code/YourVendor/YourModule/etc/di.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="CustomProductWithPlugin" type="YourVendor\YourModule\Model\CustomProduct">
<arguments>
<argument name="enablePlugin" xsi:type="boolean">true</argument>
</arguments>
</virtualType>
<virtualType name="CustomProductWithoutPlugin" type="YourVendor\YourModule\Model\CustomProduct">
<arguments>
<argument name="enablePlugin" xsi:type="boolean">false</argument>
</arguments>
</virtualType>
</config>
<type name="YourVendor\YourModule\Model\ProductRepository">
<arguments>
<argument name="product" xsi:type="object">CustomProductWithPlugin</argument>
</arguments>
</type>
Step 3: Create the Plugin
Develop a plugin that modifies the product’s behavior based on the enablePlugin
flag. For demonstration, we’ll append a suffix to the product name if enablePlugin
is true
.
File: app/code/YourVendor/YourModule/Plugin/ProductPlugin.php
namespace YourVendor\YourModule\Plugin;
use Magento\Catalog\Api\Data\ProductInterface;
class ProductPlugin
{
/**
* Modify the product name after it is retrieved if enablePlugin is true.
*
* @param ProductInterface $subject
* @param string $result
* @return string
*/
public function afterGetName(ProductInterface $subject, string $result): string
{
if (!$subject->getEnablePlugin()) {
return $result;
}
// Append a custom suffix to the product name
return $result . ' - Custom Suffix';
}
}
Step 4: Write Unit Tests
Implement unit tests to verify that the plugin behaves as expected when enablePlugin
is true
or false
.
File: app/code/YourVendor/YourModule/Test/Unit/Plugin/ProductPluginTest.php
namespace YourVendor\YourModule\Test\Unit\Plugin;
use PHPUnit\Framework\TestCase;
use YourVendor\YourModule\Plugin\ProductPlugin;
use YourVendor\YourModule\Model\CustomProduct;
class ProductPluginTest extends TestCase
{
public function testAfterGetNameWithPluginEnabled()
{
$product = $this->createMock(CustomProduct::class);
$product->method('getEnablePlugin')->willReturn(true);
$product->method('getName')->willReturn('Original Name');
$plugin = new ProductPlugin();
$result = $plugin->afterGetName($product, $product->getName());
$this->assertEquals('Original Name - Custom Suffix', $result);
}
public function testAfterGetNameWithPluginDisabled()
{
$product = $this->createMock(CustomProduct::class);
$product->method('getEnablePlugin')->willReturn(false);
$product->method('getName')->willReturn('Original Name');
$plugin = new ProductPlugin();
$result = $plugin->afterGetName($product, $product->getName());
$this->assertEquals('Original Name', $result);
}
}
Practical Considerations
While this approach demonstrates Magento’s flexibility, it introduces complexity that may not be necessary for all scenarios. In many cases, a single plugin with conditional logic based on product attributes can achieve similar results with less overhead. It’s essential to assess the specific needs of your project before implementing such a design.
By following this guide, you’ve explored how to create a dynamic Magento plugin using virtualType
and DI, with unit tests to ensure functionality. This theoretical approach showcases the potential of Magento’s architecture for creating modular and adaptable solutions.
Join the Conversation
Have thoughts about this approach? Share your experience or feedback!
- What do you think about using
virtualType
in this way? Have you implemented a similar solution, or do you prefer alternative approaches? - Are there scenarios where this approach would be particularly useful for your projects?
- What challenges have you faced when combining plugins and
virtualType
in Magento?
Feel free to leave a comment below or start a discussion. Your insights can help others in the Magento development community!
Comments