Magento 2: Models, Resource Models, and Collections

Models in Magento are an inherent part of the MVC (Model-View-Controller) architecture. Models are used to do data operations, namely Create, Read, Update and Delete, on a database. Magento’s “Model system” is divided into three parts - models, resource models, and collections. In this tutorial, we will be discussing each component individually, and then use all three to make a simple module.

If you wanna follow along, first you’ll have to create a simple hello world module, and then create a table called “my_cars” containing the columns "car_id", "manufacturer", and "model", using an Install Schema setup script.

Model

Models are like a black box which provides a layer of abstraction on top of the resource models. The fetching, extraction, and manipulation of data occur through models. As a rule of thumb, every entity we create (i.e. every table we create in our database) should have its own model class. Every model extends the Magento\Framework\Model\AbstractModelclass, which inherits the \Magento\Framework\DataObjectclass, hence, we can call the setDataand getData functions on our model, to get or set the data of a model respectively. To understand how data objects work, you can read the tutorial on data objects here.

app/code/Jayanka/HelloWorld/Model/Car.php

<?php

namespace Jayanka\HelloWorld\Model;

use Magento\Framework\Model\AbstractModel;
use Jayanka\HelloWorld\Model\ResourceModel\Car as ResourceModel;

class Car extends AbstractModel
{
    protected function _construct()
    {
        $this->_init(ResourceModel::class);
    }
}

The Carclass only has one method, _construct(), when we call the _init()method, and pass the resource model’s name as its parameter. But what is a resource model?

Resource Model

All of the actual database operations are executed by the resource model. Every model must have a resource model, since all of the methods of a resource model expects a model as its first parameter. All resource models must extend the Magento\Framework\Model\ResourceModel\Db\AbstractDbclass.

app/code/Jayanka/HelloWorld/Model/ResourceModel/Car.php

<?php

namespace Jayanka\HelloWorld\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Car extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('my_cars', 'car_id');
    }
}

As we can see, the <Carclass> here also has one method, <__construct>, where we call the <_initmethod>, and pass two parameters to it. The name of the table in the database, and the name of the primary column in that table.

Collection

Collections are used when we want to fetch multiple rows from our table. Meaning collections are a group of models. Collections can be used when we want to

 

app/code/Jayanka/HelloWorld/Model/ResourceModel/Car/Collection.php

<?php
namespace Jayanka\HelloWorld\Model\ResourceModel\Car;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Jayanka\HelloWorld\Model\Car as Model;
use Jayanka\HelloWorld\Model\ResourceModel\Car as ResourceModel;

class Collection extends AbstractCollection
{
    protected function _construct()
    {
        $this->_init(Model::class, ResourceModel::class);
    }
}

All collections must inherit the <Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection> class. Our collection class also has one method, the <_construct>, where we call the <_init>method and pass two arguments, the name of the model class, and the resource model class.

Using our Model

Now that our Model, ResourceModel, and Collection classes are ready, let’s use them.

app/code/Jayanka/HelloWorld/Block/Hello.php

<?php
/**
 *
 * @package     magento2
 * @author      Jayanka Ghosh
 * @license     https://opensource.org/licenses/OSL-3.0 Open Software License v. 3.0 (OSL-3.0)
 * @link        http://jayanka.me/
 */

namespace Jayanka\HelloWorld\Block;


use Magento\Framework\View\Element\Template;
use Jayanka\HelloWorld\Model\ResourceModel\Car\Collection;

class Hello extends Template
{
    /**
     * @var Collection
     */
    private $collection;

    /**
     * Hello constructor.
     * @param Template\Context $context
     * @param Collection $collection
     * @param array $data
     */
    public function __construct(
        Template\Context $context,
        Collection $collection,
        array $data = []
    )
    {
        parent::__construct($context, $data);
        $this->collection = $collection;
    }

    public function getAllCars() {
        return $this->collection;
    }

    public function getAddCarPostUrl() {
        return $this->getUrl('helloworld/car/add');
    }

}

and in our template file we add a form to add new cars, and a table, listing all the existing cars in the database

app/code/Jayanka/HelloWorld/view/frontend/templates/hello.phtml

<?php
/* @var Jayanka\HelloWorld\Block\Hello $block */
$cars = $block->getAllCars();
?>

<form method="post" action="<?= $block->getAddCarPostUrl() ?>">
   <fieldset>
       <div>
            <label for="manufacturer"><?= __("Manufacturer") ?></label>
           <input type="text" name="manufacturer" id="manufacturer" />
      </div>
       <div>
            <label for="model"><?= __("Model") ?>
           <input type="text" name="model" id="model" />
       </div>
      <input type="submit" value="<?= __("Add Car") ?>" />
   </fieldset>
</form>
<hr />
<?php if (count($cars) > 0): ?>
 <table border="1">
      <tr>
         <th><?= __("ID") ?></th>
          <th><?= __("Manufacturer") ?>
            <?= __("Model") ?></th>
        </tr>
       <?php foreach ($cars as $car): ?>
            <tr>
               <td><?= $car->getId() ?>
               <td><?= $car->getManufacturer() ?>
              <td><?= $car->getModel() ?>
           </tr>
      <?php endforeach; ?>
    </table>
<?php else: ?>
    <h1><?= __("You have no cars yet :(") ?></h1>
<?php endif; ?>

Now finally we have to make a controller to save the car information submitted from the form

app/code/Jayanka/HelloWorld/Controller/Car/Add.php

<?php
/**
 *
 * @package     magento2
 * @author      Codilar Technologies
 * @license     https://opensource.org/licenses/OSL-3.0 Open Software License v. 3.0 (OSL-3.0)
 * @link        http://www.codilar.com/
 */

namespace Jayanka\HelloWorld\Controller\Car;


use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Jayanka\HelloWorld\Model\Car;
use Jayanka\HelloWorld\Model\ResourceModel\Car as CarResource;

class Add extends Action
{
    /**
     * @var Car
     */
    private $car;
    /**
     * @var CarResource
     */
    private $carResource;

    /**
     * Add constructor.
     * @param Context $context
     * @param Car $car
     * @param CarResource $carResource
     */
    public function __construct(
        Context $context,
        Car $car,
        CarResource $carResource
    )
    {
        parent::__construct($context);
        $this->car = $car;
        $this->carResource = $carResource;
    }

    /**
     * Execute action based on request and return result
     *
     * Note: Request will be added as operation argument in future
     *
     * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface
     * @throws \Magento\Framework\Exception\NotFoundException
     */
    public function execute()
    {
        /* Get the post data */
        $data = $this->getRequest()->getParams();

        /* Set the data in the model */
        $carModel = $this->car;
        $carModel->setData($data);

        try {
            /* Use the resource model to save the model in the DB */
            $this->carResource->save($carModel);
            $this->messageManager->addSuccessMessage("Car saved successfully!");
        } catch (\Exception $exception) {
            $this->messageManager->addErrorMessage(__("Error saving car"));
        }

        /* Redirect back to cars page */
        $redirect = $this->resultRedirectFactory->create();
        $redirect->setPath('helloworld');
        return $redirect;
    }
}

Now, when we open our favourite browser, and hit the URL http://mywebsite.com/helloworld/, we should be able to see our car list.

That's all there is to know about the basics of models in Magento. If you want us to make a tutorial blog post about a particular topic comment below.