Table of Contents
- Introduction
- What Is the Factory Pattern?
- How Magento 2 Implements Factories
- How the Generated Factory Works
- Important Modern Magento Best Practice
- Updated Real Example
- Key Correction
- Real-World Use Cases
- Common Mistakes
- When to Use Factories
- When NOT to Use Factories
- Factories & Magento Upgrades
- Conclusion
Factory Pattern in Magento 2: Object Creation the Right Way
Introduction
Imagine a feature where you need to create product instances dynamically based on user input.
Your first instinct might be:
$product = new \Magento\Catalog\Model\Product();
This creates multiple problems:
- Tight coupling to a concrete class
- Breaks Magento’s Dependency Injection (DI) principles
- Hard to test (no mocking possible)
- Future upgrades become riskyIn Magento, you should NEVER instantiate models using new directly.
This is where the Factory Pattern comes in.
What Is the Factory Pattern?
The Factory Pattern is a creational design pattern used to create objects without exposing instantiation logic.
Structure:
Client → Factory → Object Instance
Why it matters in Magento:
- Decouples business logic from concrete classes
- Ensures fresh instances (no shared mutable state)
- Enables testability via mocking
- Aligns with Magento’s DI system
How Magento 2 Implements Factories
Auto-Generated Factories (Important Correction)
You DO NOT need to define factories in di.xml.
This is unnecessary:
Correct approach: Just inject the factory
use Magento\Catalog\Model\ProductFactory; public function __construct( ProductFactory $productFactory ) { $this->productFactory = $productFactory; } // Magento automatically generates: generated/code/Magento/Catalog/Model/ProductFactory.php
How the Generated Factory Works
Magento internally generates something like:
public function create(array $data = []) { return $this->_objectManager->create( \Magento\Catalog\Model\Product::class, $data ); }
Note:
- Uses $data (not $arguments)
- Fully qualified class constant
- Managed by Object Manager internally (never use directly)
Important Modern Magento Best Practice
Do NOT use ProductFactory for creating products in business logic
Magento now strongly promotes:
Service Contracts + Repositories
Factories are for:
- Internal model instantiation
- Framework-level usage
For business logic (like product creation):
Use \Magento\Catalog\Api\Data\ProductInterfaceFactory
Updated Real Example: Product Creation
Service Class (Modern Approach)
namespace Vendor\ProductImport\Model;
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
use Magento\Catalog\Api\ProductRepositoryInterface;
class ProductCreator
{
private ProductInterfaceFactory $productFactory;
private ProductRepositoryInterface $productRepository;
public function __construct(
ProductInterfaceFactory $productFactory,
ProductRepositoryInterface $productRepository
) {
$this->productFactory = $productFactory;
$this->productRepository = $productRepository;
}
public function createFromData(array $data)
{
$product = $this->productFactory->create();
$product->setSku($data['sku'] ?? '');
$product->setName($data['name'] ?? '');
$product->setPrice((float)($data['price'] ?? 0));
$product->setAttributeSetId($data['attribute_set_id'] ?? 4);
$product->setTypeId($data['type_id'] ?? 'simple');
$product->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED);
$product->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH);
return $this->productRepository->save($product);
}
}
Why this is correct:
- Uses interface factory (recommended)
- Works with service contracts
- Future-proof and upgrade-safe
Key Correction: Factory vs Repository
Your original statement:
“Don’t inject ProductFactory alongside a repository.”
This is incorrect / misleading
Correct rule:
- Use Factory → create new instance
- Use Repository → persist / fetch
They are used together, not mutually exclusive.
Real-World Use Cases
1. Collections (Correct Example)
public function getProductsByCategory($categoryId) { $collection = $this->productCollectionFactory->create(); $collection->addCategoriesFilter(['in' => $categoryId]); $collection->addAttributeToFilter( 'status', \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED ); return $collection; }
Fixed:
- Correct filter method
- Avoid magic numbers (1)
2. Shipment Creation (Better Practice Note)
Your shipment example is valid but incomplete.
In real Magento:
- Use ShipmentFactory + ShipmentRepository
- Often handled via service classes (ShipmentManagementInterface)
Common Mistakes
Mistake: Using Model Factory Instead of Interface Factory
// Not recommended for service layer
\ProductFactory $productFactory
Use:
ProductInterfaceFactory $productFactory
Mistake: Using ObjectManager Directly
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$product = $objectManager->create(…);
Strictly forbidden in production code.
Mistake: VirtualType for Factory Customization
Factories are auto-generated → customization via virtualType is rarely needed and often overengineering.
When to Use Factories
Use when:
- Creating multiple instances (loops, batch jobs)
- Working with collections (CollectionFactory)
- Using interface-based models (*InterfaceFactory)
- Avoiding ObjectManager
When NOT to Use Factories
Do NOT use when:
- You can fetch via repository (getById, getList)
- Working with stateless services
- You need shared instances (use DI instead)
Factories & Magento Upgrades
Your concept is correct, but slightly exaggerated.
Accurate statement:
Factories help because:
- Constructor changes are abstracted
- DI container handles dependencies
- Reduces direct dependency on concrete classes
But:
- They do NOT eliminate all upgrade issues
- API changes (interfaces) still affect code
Factory vs Proxy (Clarified)
| Pattern | Purpose |
|---|---|
| Factory | Create new instances |
| Proxy | Lazy-load heavy dependencies |
Example:
name="productRepository"
xsi:type="object">
Magento\Catalog\Api\ProductRepositoryInterface\Proxy
Conclusion
The Factory Pattern in Magento is not optional it’s foundational.
But modern Magento development requires a balanced approach:
Follow this hierarchy:
- Service Contracts (Interfaces)
- Repositories (Persistence)
- Factories (Instance creation)
Key Takeaways:
- Prefer *InterfaceFactory over model factories
- Use factories + repositories together
- Never use new or ObjectManager
- Keep services small and testable
- Align with Magento’s DI architecture
