Back to Top

Magento 2 Development 24: Loading Magento’s Data

Updated 12 March 2024

We have seen how to use the custom table’s collections. Obviously Magento have model and collections for customers, products, orders, etc. So in this blog, we will use customer and product collections. But at the end of this blog, I will provide you with some recommended exercises. Please implement those so that you get a better understanding.

In this blog, we will allow the admin to assign a blog to any author. Also, the admin will be able to add related products to the blog.

Customer Collection

We will add the assign author feature in the status tab only. So let’s edit the Block/Adminhtml/Blog/Edit/Tab/Status.php

<?php
namespace Webkul\BlogManager\Block\Adminhtml\Blog\Edit\Tab;

class Status extends \Magento\Backend\Block\Widget\Form\Generic
{
    /**
     * @var \Webkul\BlogManager\Model\Blog\Status
     */
    protected $blogStatus;

    /**
     * @var \Magento\Customer\Model\CustomerFactory
     */
    protected $customerFactory;

    /**
     * Dependency Initilization
     *
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\Data\FormFactory $formFactory
     * @param \Webkul\BlogManager\Model\Blog\Status $blogStatus
     * @param \Magento\Customer\Model\CustomerFactory $customerFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Webkul\BlogManager\Model\Blog\Status $blogStatus,
        \Magento\Customer\Model\CustomerFactory $customerFactory,
        array $data = []
    ) {
        $this->blogStatus = $blogStatus;
        $this->customerFactory = $customerFactory;
        parent::__construct($context, $registry, $formFactory, $data);
    }

    /**
     * Prepare form data
     *
     * @return \Magento\Backend\Block\Widget\Form
     */
    protected function _prepareForm()
    {
        $model = $this->_coreRegistry->registry('blog_data');

        $form = $this->_formFactory->create();

        $form->setHtmlIdPrefix('blogmanager_');

        $fieldset = $form->addFieldset(
            'base_fieldset',
            ['legend' => __('Edit Blog'), 'class' => 'fieldset-wide']
        );

        $fieldset->addField(
            'status',
            'select',
            [
                'name' => 'status',
                'label' => __('Status'),
                'options' => [0=>__('Disabled'), 1=>__('Enabled')],
                'id' => 'status',
                'title' => __('Status'),
                'class' => 'required-entry',
                'required' => true,
            ]
        );

        $fieldset->addField(
            'user_id',
            'select',
            [
                'name' => 'user_id',
                'label' => __('Author'),
                'options' => $this->getAuthorOptions(),
                'id' => 'user_id',
                'title' => __('Author'),
                'class' => 'required-entry',
                'required' => true,
            ]
        );

        $form->setValues($model->getData());
        $this->setForm($form);

        return parent::_prepareForm();
    }

    /**
     * Provides Author options
     *
     * @return array
     */
    private function getAuthorOptions()
    {
        $collection = $this->customerFactory->create()->getCollection();
        $authors = [0=>'Admin'];
        foreach ($collection as $model) {
            $authors[$model->getId()] = $model->getName();
        }
        return $authors;
    }
}

We have used \Magento\Customer\Model\CustomerFactory which is a model for customer data. And in the getAuthorOptions function, we have loaded the collection through the model. After that, we created an associative array of $authors which will be used for options. In the $authors array we have added an entry for admin too with the id as 0.
Note that we could have also used the collection class \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory.

Now you will see the field as shown below,

Searching for an experienced
Magento 2 Company ?
Find out More
2021-07-22_16-22


Product Collection

Let’s add the related product feature. For that, we will create a new tab which means we will have to edit the Block/Adminhtml/Blog/Edit/Tabs.php

Updated code for Block/Adminhtml/Blog/Edit/Tabs.php file

<?php
namespace Webkul\BlogManager\Block\Adminhtml\Blog\Edit;

class Tabs extends \Magento\Backend\Block\Widget\Tabs
{
    /**
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry;

    /**
     * Dependency Initilization
     *
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
     * @param \Magento\Backend\Model\Auth\Session $authSession
     * @param \Magento\Framework\Registry $coreRegistry
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
        \Magento\Backend\Model\Auth\Session $authSession,
        \Magento\Framework\Registry $coreRegistry,
        array $data = []
    ) {
        $this->_coreRegistry = $coreRegistry;
        parent::__construct($context, $jsonEncoder, $authSession, $data);
    }

    /**
     * Dependency Initilization
     *
     * @return void
     */
    protected function _construct()
    {
        parent::_construct();
        $this->setId('blog_tabs');
        $this->setDestElementId('edit_form');
        $this->setTitle(__('Blog Data'));
    }

    /**
     * Prepare form data
     *
     * @return \Magento\Backend\Block\Widget\Form
     */
    protected function _prepareLayout()
    {
        $this->addTab(
            'main',
            [
                'label' => __('Blog Data'),
                'content' => $this->getLayout()->createBlock(
                    'Webkul\BlogManager\Block\Adminhtml\Blog\Edit\Tab\Main'
                )->toHtml(),
                'active' => true
            ]
        );

        $this->addTab(
            'status',
            [
                'label' => __('Blog Status'),
                'content' => $this->getLayout()->createBlock(
                    'Webkul\BlogManager\Block\Adminhtml\Blog\Edit\Tab\Status'
                )->toHtml()
            ]
        );

        $this->addTab(
            'related_products',
            [
                'label' => __('Related Products'),
                'content' => $this->getLayout()->createBlock(
                    'Webkul\BlogManager\Block\Adminhtml\Blog\Edit\Tab\RelatedProducts'
                )->toHtml()
            ]
        );

        return parent::_prepareLayout();
    }
}

Here we have just added a new tab with $this->addTab function.

Now let’s write code for the related products tab. We will create the class as Block/Adminhtml/Blog/Edit/Tab/RelatedProducts.php

Code for Block/Adminhtml/Blog/Edit/Tab/RelatedProducts.php file

<?php
namespace Webkul\BlogManager\Block\Adminhtml\Blog\Edit\Tab;

class RelatedProducts extends \Magento\Backend\Block\Widget\Form\Generic
{
    /**
     * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
     */
    protected $productCollectionFactory;

    /**
     * Dependency Initilization
     *
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\Data\FormFactory $formFactory
     * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
        array $data = []
    ) {
        $this->productCollectionFactory = $productCollectionFactory;
        parent::__construct($context, $registry, $formFactory, $data);
    }

    /**
     * Prepare form data
     *
     * @return \Magento\Backend\Block\Widget\Form
     */
    protected function _prepareForm()
    {
       
        $model = $this->_coreRegistry->registry('blog_data');

        $form = $this->_formFactory->create();

        $form->setHtmlIdPrefix('blogmanager_');

        $fieldset = $form->addFieldset(
            'base_fieldset',
            ['legend' => __('Related Products'), 'class' => 'fieldset-wide']
        );

        $fieldset->addField(
            'products',
            'multiselect',
            [
                'name' => 'products',
                'label' => __('Products'),
                'values' => $this->getProductOptions(),
                'id' => 'products',
                'title' => __('Products'),
                'required' => false,
            ]
        );

        $form->setValues($model->getData());
        $this->setForm($form);

        return parent::_prepareForm();
    }

    /**
     * Get Product Options
     *
     * @return array
     */
    private function getProductOptions()
    {
        $collection = $this->productCollectionFactory->create()->addAttributeToSelect('name');
        $products = [];
        foreach ($collection as $model) {
            $products[] = ['value'=>$model->getId(), 'label'=>$model->getName()];
        }
        return $products;
    }
}

Here we have used the products collection class which is \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory but could have also used the model which is \Magento\Catalog\Model\ProductFactory. One more thing to note here is ->addAttributeToSelect(‘name’) since there is a lot of data for a product. By default, Magento only loads basic details such as id, sku, type, etc. So we have to use addAttributeToSelect to load the additional fields such as name here.

Also please note that it is a multi-select type field so the syntax for the field and option is a little bit different than what we have seen so far.

Now you should see the related products tab like,

2021-07-22_16-44


It looks well and good but we won’t be able to save the data yet. First of all, we will have to create a new column in the table for the related products. Also, we have to modify the save controller a little bit.

To add the column let’s modify the db schema etc/db_schema.xml

Updated code for db schema etc/db_schema.xml file

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="blogmanager_blog" resource="default" engine="innodb" comment="Blogs Table">
        <column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity Id"/>
        <column xsi:type="int" name="user_id" padding="10" unsigned="true" nullable="false" comment="Customer/User Id"/>
        <column xsi:type="varchar" name="title" nullable="false" length="255" comment="Blog Title"/>
        <column xsi:type="longtext" name="content" nullable="false" comment="Blog Content"/>
        <column xsi:type="smallint" name="status" padding="11" unsigned="false" nullable="false" default="0" comment="Blog Status"/>
        <column xsi:type="timestamp" name="created_at" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="Creation Time"/>
        <column xsi:type="timestamp" name="updated_at" on_update="true" nullable="false" default="CURRENT_TIMESTAMP" comment="Updated At"/>
        <column xsi:type="varchar" name="products" nullable="false" length="255" comment="Related products"/>
        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="entity_id"/>
        </constraint>
        <index referenceId="BLOGMANAGER_BLOG_USER_ID" indexType="btree">
            <column name="user_id"/>
        </index>
    </table>
    <table name="blogmanager_comment" resource="default" engine="innodb" comment="Blog Comments Table">
        <column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity Id"/>
        <column xsi:type="int" name="blog_id" padding="10" unsigned="true" nullable="false" comment="Blog Id"/>
        <column xsi:type="int" name="user_id" padding="10" unsigned="true" nullable="false" comment="User Id"/>
        <column xsi:type="varchar" name="screen_name" nullable="false" length="255" comment="Screen Name"/>
        <column xsi:type="text" name="comment" nullable="false" comment="Comment"/>
        <column xsi:type="smallint" name="status" padding="11" unsigned="false" nullable="false" default="0" comment="Status"/>
        <column xsi:type="timestamp" name="created_at" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="Creation Time"/>
        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="entity_id"/>
        </constraint>
        <constraint xsi:type="foreign" referenceId="FK_BLOG_COMMENT" table="blogmanager_comment" column="blog_id" referenceTable="blogmanager_blog" referenceColumn="entity_id" onDelete="CASCADE"/>
        <index referenceId="BLOGMANAGER_COMMENT_BLOG_ID" indexType="btree">
            <column name="blog_id"/>
        </index>
    </table>
</schema>

We have just added a column tag to add the column and the name of the column is products. Now we have to run these commands if you recall from Magento 2 Development 03: Creating Tables blog.

php bin/magento setup:db-declaration:generate-whitelist --module-name=Webkul_BlogManager

php bin/magento setup:upgrade


Now we have to write code to save the values in db. So we will edit Controller/Adminhtml/Manage/Save.php

Updated code for Controller/Adminhtml/Manage/Save.php file

<?php
namespace Webkul\BlogManager\Controller\Adminhtml\Manage;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;

class Save extends Action
{
    /**
     * @var \Webkul\BlogManager\Model\BlogFactory
     */
    protected $blogFactory;

    /**
     * Dependency Initilization
     *
     * @param Context $context
     * @param \Webkul\BlogManager\Model\BlogFactory $blogFactory
     */
    public function __construct(
        Context $context,
        \Webkul\BlogManager\Model\BlogFactory $blogFactory
    ) {
        $this->blogFactory = $blogFactory;
        parent::__construct($context);
    }

    /**
     * Provides content
     *
     * @return Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        $resultRedirect = $this->resultRedirectFactory->create();
        $data = $this->getRequest()->getParams();
        if (isset($data['entity_id']) && $data['entity_id']) {
            $model = $this->blogFactory->create()->load($data['entity_id']);
            $model->setTitle($data['title'])
                ->setContent($data['content'])
                ->setStatus($data['status'])
                ->setUserId($data['user_id']);
            if (isset($data['products'])) {
                $model->setProducts(implode(',', $data['products']));
            } else {
                $model->setProducts('');
            }
            $model->save();
            $this->messageManager->addSuccess(__('You have updated the blog successfully.'));
        } else {
            $model = $this->blogFactory->create();
            $model->setTitle($data['title'])
                ->setContent($data['content'])
                ->setStatus($data['status'])
                ->setUserId($data['user_id']);
            if (isset($data['products'])) {
                $model->setProducts(implode(',', $data['products']));
            } else {
                $model->setProducts('');
            }
            $model->save();
            $this->messageManager->addSuccess(__('You have successfully created the blog.'));
        }
        return $resultRedirect->setPath('*/*/');
    }

    /**
     * Check Autherization
     *
     * @return boolean
     */
    public function _isAllowed()
    {
        return $this->_authorization->isAllowed('Webkul_BlogManager::save');
    }
}

We have set the fields just like before. But there are minor changes for the $data[‘products’] field to check whether the Related Products are set or not. Also, the $data[‘products’] is a multi-select type field we have used the implode function to convert to string.

We are done now. You should be able to save all the fields.

Repository

We have seen how we can use models to perform CRUD operations. Magento 2 has another thing called Repository to perform these operations. You can think of repositories as higher level implementation than the factories. Repositories have fixed methods like get, list, save, and delete. Magento recommends using the corresponding repositories instead of the model.

Please go through this blog and also google “Repository in Magento 2” and “Difference between Repository and Factory in Magento 2” to get a better understanding.

Magento2 Repository Design Pattern


Recommended Exercises

Please implement these recommended exercises on the front-end. Try with the factory and repository to get a better idea about them.

1. List orders of a customer given the email id.
2. List items of an order given the order increment id.
3. List products and quantity purchased by a customer given the customer name (assume customers have unique names).
4. Implement product search functionality based on the product name and sku with the sort by price and pagination feature.
5. Print the category tree structure.


Next Blog -> Magento 2 Development 25: Helper

Previous Blog -> Magento 2 Development 23: Add Button

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


Be the first to comment.

Back to Top

Message Sent!

If you have more details or questions, you can reply to the received confirmation email.

Back to Home