Magento 2 Factory Objects

In object oriented programming, a factory method is a method that’s used to instantiate an object. Factory methods exist to ensure system developers have control over how a particular object is instantiated, and how its arguments are passed in. There’s a certain school of though that thinks direct use of the new keyword in programming

$object = new Foo;

is an anti-pattern, as directly instantiating an object creates a hard coded dependency in a method. Factory methods give the system owner the ability to control which objects are actually returned in a given context.

A factory object serves a similar purpose. In Magento 2, each CRUD model has a corresponding factory class. All factory class names are the name of the model class, appended with the word “Factory”. So, since our model class is named

Pulsestorm/ToDoCrud/Model/TodoItem

this means our factory class is named

Pulsestorm/ToDoCrud/Model/TodoItemFactory

To get an instance of the factory class, replace your block class with the following.

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php    
<?php
namespace Pulsestorm\ToDoCrud\Block;
class Main extends \Magento\Framework\View\Element\Template
{
    protected $toDoFactory;
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Pulsestorm\ToDoCrud\Model\TodoItemFactory $toDoFactory
    )
    {
        $this->toDoFactory = $toDoFactory;
        parent::__construct($context);
    }

    function _prepareLayout()
    {
        var_dump(
            get_class($this->toDoFactory)
        );
        exit;
    }
}

What we’ve done here is use automatic constructor dependency injection to inject a Pulsestorm\ToDoCrud\Model\TodoItemFactory factory object, and assign it to the toDoFactory object property in the constructor method.

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php        
protected $toDoFactory;
public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Pulsestorm\ToDoCrud\Model\TodoItemFactory $toDoFactory
)
{
    $this->toDoFactory = $toDoFactory;
    parent::__construct($context);
}

We also had to inject a block context object and pass that to our parent constructor. We’ll cover these context object in future articles, but if you’re curious about learning more, this quickies post is a good place to start.

In addition to injecting a factory into our block, we also added the following to our _prepareLayout method

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php    
function _prepareLayout()
{
    var_dump(
        get_class($this->toDoFactory)
    );
    exit;
}

This will dump the toDoFactory‘s class name to the screen, and is a quick sanity check that our automatic constructor dependency injection worked. Reload your page with the above in place, and you should see the following

string 'Pulsestorm\ToDoCrud\Model\TodoItemFactory' (length=41)

Next, replace your _prepareLayout method with this code

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php    

function _prepareLayout()
{
    $todo = $this->toDoFactory->create();
    $todo->setData('item_text','Finish my Magento article')
    ->save();
    var_dump('Done');
    exit;
}

This code calls the create method of our factory. This will instantiate a \Pulsestorm\ToDoCrud\Model\TodoItemFactory object for us. Then, we set the item_textproperty of our model, and call its save method. Reload your page to run the above code, and then check your database table

mysql> select * from pulsestorm_todocrud_todoitem\G
*************************** 1. row ***************************
pulsestorm_todocrud_todoitem_id: 1
                      item_text: Finish my Magento article
                 date_completed: NULL
                  creation_time: NULL
                    update_time: NULL
                      is_active: 1
1 row in set (0.00 sec)

You’ll find that Magento has saved the information you requested. If you wanted to fetch this specific model again, you’d use code that looked like the following.

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php        
function _prepareLayout()
{
    $todo = $this->toDoFactory->create();

    $todo = $todo->load(1);        
    var_dump($todo->getData());
    exit;
}

Here we’ve used the factory to create our model, used the model’s load method to load a model with the ID of 1, and then dumped the model’s data using the various magic setter and getter methods available to a Magento 2 model.

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php        
function _prepareLayout()
{
    $todo = $this->toDoFactory->create();

    $todo = $todo->load(1);        

    var_dump($todo->getData());

    var_dump($todo->getItemText());

    var_dump($todo->getData('item_text'));
    exit;
}

Finally, if we wanted to use a CRUD model’s collection object, we’d use code that looked like this

#File: app/code/Pulsestorm/ToDoCrud/Block/Main.php          
function _prepareLayout()
{
    $todo = $this->toDoFactory->create();

    $collection = $todo->getCollection();

    foreach($collection as $item)
    {
        var_dump('Item ID: ' . $item->getId());
        var_dump($item->getData());
    }
    exit;
}   

Again, this code uses a factory object to create a CRUD model object. Then, we use the CRUD model object’s getCollection method to fetch the model’s collection. Then, we iterate over the items returned by the collection.

Once instantiated via a factory, Magento 2’s CRUD models behave very similarly, if not identically, to their Magento 1 counterparts. If you’re curious about Magento 1’s CRUD objects, our venerable Magento 1 for PHP MVC Developers article may be of interest, as well as the Varien Data Collections article.

Where did the Factory Come From

You may be thinking to yourself — how did Magento instantiate a Pulsestorm/ToDoCrud/Model/TodoItemFactory class if I never defined one? Factory classes are another instance of Magento 2 using code generation (first covered in our Proxy objectarticle). Whenever Magento’s object manager encounters a class name that ends in the word Factory, it will automatically generate the class in the var/generation folder if the class does not already exist. You can see your generated factory class at the following location

#File: var/generation/Pulsestorm/ToDoCrud/Model/TodoItemFactory.php 
<?php
namespace Pulsestorm\ToDoCrud\Model;

/**
 * Factory class for @see \Pulsestorm\ToDoCrud\Model\TodoItem
 */
class TodoItemFactory
{
    //...
}

posted on 2017-04-11 11:57  冯亮  阅读(558)  评论(0编辑  收藏  举报

导航