In summary, we want to say that Magento 2 architecture developed with Factory method usage, follows best practices in the OOP (Object Oriented Programming) world and SOLID principles. Automatically generated factories are the way the pattern is commonly used by platform for Data object initialization. The Factory method also allows decoupling objects and provides a layer between the business code and Object manager.
It is worth mentioning that automatically generated factories are not the only place where such approach is widely used. Our next article will be dedicated to the Command pattern, where we will highlight the importance of Factory method usage and other patterns to achieve a well-structured and flexible software architecture. Stay tuned to learn how the reviewed patterns (Object manager, Factory method) can do magic together with the Command pattern.
Content
- General Overview
- Generated Factories
- Factory Constructor
- Factory Create Method
- Factory Method Usage
- Summary
Factories create method in the Factory class generator combines from the next parts:
Factory method usage is aimed at the new object initialization by following a specific contract of decoupling objects. Like in all other software applications architecture, Magento 2 uses such an approach for handling object generations. The most frequently used aspect is the Data object initialization on the service layer.
GOF – Factory Method Pattern.
One of the core Magento 2 features is code generation. In the official documentation, there is an excellent article that explains the benefits of code generation — highly recommended reading. We will not dig too deep into this material, but will say that code generation simplifies Data object factory generation.
The magic of the factories’ generation can be clearly seen in the MagentoFrameworkObjectManagerCodeGeneratorFactory. This class has a predefined structure with required parts of the factory. Let’s review this generator class and CustomerInterfaceFactory in detail.
In Magento 2, Factory uses Object manager, and Object manager uses Factory. Before going further, we recommend reading the previous blog post that will help in forming a more solid understanding of both patterns and their applicability approach in Magento 2.
The Data object is a part of the Service layer of the Magento 2 architecture and represents entities – such as Customer or Catalog. /** * Get default constructor definition for generated class * * @return array */ protected function _getDefaultConstructorDefinition() { return [ ‘name’ => ‘__construct’, ‘parameters’ => [ [‘name’ => ‘objectManager’, ‘type’ => ‘\’ . MagentoFrameworkObjectManagerInterface::class], [‘name’ => ‘instanceName’, ‘defaultValue’ => $this->getSourceClassName()], ], ‘body’ => “$this->_objectManager = $objectManager;n$this->_instanceName = $instanceName;”, ‘docblock’ => [ ‘shortDescription’ => ucfirst(static::ENTITY_TYPE) . ‘ constructor’, ‘tags’ => [ [ ‘name’ => ‘param’, ‘description’ => ‘MagentoFrameworkObjectManagerInterface $objectManager’, ], [‘name’ => ‘param’, ‘description’ => ‘string $instanceName’], ], ] ]; }
/** * Returns list of methods for class generator * * @return array */ protected function _getClassMethods() { $construct = $this->_getDefaultConstructorDefinition(); // public function create(array $data = array()) $create = [ ‘name’ => ‘create’, ‘parameters’ => [[‘name’ => ‘data’, ‘type’ => ‘array’, ‘defaultValue’ => []]], ‘body’ => ‘return $this->_objectManager->create($this->_instanceName, $data);’, ‘docblock’ => [ ‘shortDescription’ => ‘Create class instance with specified parameters’, ‘tags’ => [ [‘name’ => ‘param’, ‘description’ => ‘array $data’], [ ‘name’ => ‘return’, ‘description’ => $this->getSourceClassName() ], ], ], ]; return [$construct, $create]; }
/** * Factory constructor * * @param MagentoFrameworkObjectManagerInterface $objectManager * @param string $instanceName */ public function __construct( MagentoFrameworkObjectManagerInterface $objectManager, $instanceName = ‘\Magento\Customer\Api\Data\CustomerInterface’ ) { $this->_objectManager = $objectManager; $this->_instanceName = $instanceName; }
Factory Create Method
We can assume that the Factory method is one of the most commonly used ones in creational design patterns. Such traction is based on the necessity of flexible object initialization by a contract (interface). According to the GOF (The “Gang of Four”: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides) the Factory method is:
“The Factory Method pattern defines an interface for creating an object, but lets the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses, which is useful for constructing individual objects for a specific purpose without the requestor knowing the specific class being instantiated.
For example, some Data objects are declared in the Api/Data/Data-object-name-Interface. To generate a new instance of this object, Magento 2 provides the following algorithm: use Api/Data/Data-object-name-Interface + suffix Factory. This will tell the Magento 2 framework to use (or generate if not existing) a new factory class and will allow using it in the application. The inner structure of the factory has already been described above.
Considering limitations, there is no from the Magento 2 perspective. The Factory Method is simple to use and doesn’t have any negative effects on application layers.
Let’s shift our focus on the body of the method and review it on the automatically generated example:
- name of the method – create
- method parameters – a not required data array that consists of initialized class properties and their values
- body – “the core” of the Factory: code responsible for the new object instance generation
- Dockblock and tags – contains additional information
According to their interface declaration, the Factory method is the best approach to generate new instances of those objects. But this means that for each Data entity interface, the developer has to create a separate factory implementation. Sounds like an overhead from the developer perspective. Doesn’t it? Magento 2 has a nice feature for such case, and we will review it in detail.
Simply speaking, the software application has a defined contract for specific object initialization and Factory method is a tool that guarantees this contract’s fulfillment for different classes. This helps in decoupling of both objects and their construction. SOLID in all its beauty. In Magento 2 the Factory method plays an essential role for all layers of the whole application. Let’s review this in more details in the next sections.
/** * Create class instance with specified parameters * * @param array $data * @return MagentoCustomerApiDataCustomerInterface */ public function create(array $data = []) { return $this->_objectManager->create($this->_instanceName, $data); }
“The Factory Method pattern defines an interface for creating an object, but lets the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses, which is useful for constructing individual objects for a specific purpose without the requestor knowing the specific class being instantiated.” – GOF – Factory Method Pattern. We are happy to introduce the second article in the series dedicated to Design Patterns in Magento 2. The goal of this series is to overview Magento 2 architecture with help of the design patterns explanation. The sequence of our posts is based on the logical subsequence of patterns’ usage. So the theme of the current post was selected for a reason. In the first article, we described one of the established patterns in Magento 2 – Object manager. This specific article is dedicated to Factory Method.
The code below describes the factory constructor. It consists of two parameters: Object manager and class name of the Data object entity. That is all that Factory method implementation in the Magento 2 needs in the Magento 2.