Magento 2 Development 21: Loading Magento’s Data

0

 

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 products collections. But the end of this blog I will provide you some recommended exercises. Please implement those so that you get 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
{
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);
}
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();
}
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 the customer data. And in getAuthorOptions function we have loaded the collection through the model. After that we have created an associative array $authors which will be used for options. In the $authors array we have added an entry for admin too with 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,


2021-07-22_16-22


Product Collection

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

<?php
namespace Webkul\BlogManager\Block\Adminhtml\Blog\Edit;
class Tabs extends \Magento\Backend\Block\Widget\Tabs
{
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);
}
protected function _construct()
{
parent::_construct();
$this->setId('blog_tabs');
$this->setDestElementId('edit_form');
$this->setTitle(__('Blog Data'));
}
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 the 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

<?php
namespace Webkul\BlogManager\Block\Adminhtml\Blog\Edit\Tab;
class RelatedProducts extends \Magento\Backend\Block\Widget\Form\Generic
{
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);
}
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();
}
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 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 little bit different then 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

<?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 to 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

<?php
namespace Webkul\BlogManager\Controller\Adminhtml\Manage;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
class Save extends Action
{
public $blogFactory;
public function __construct(
Context $context,
\Webkul\BlogManager\Model\BlogFactory $blogFactory
) {
$this->blogFactory = $blogFactory;
parent::__construct($context);
}
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('*/*/');
}
public function _isAllowed()
{
return $this->_authorization->isAllowed('Webkul_BlogManager::save');
}
}

We have set the fields just like before. But there are minor changes for $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 have another thing called Repository to perform these operations. You can think of repositories as higher level implementation then the factories. Repositories have fixed methods like getlist, save, delete. Magento recommends to use the corresponding repositories instead of the model.

Please go through this blog and also google about “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 front-end. Try with factory and repository both 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 customer’s have unique names).
4. Implement product search functionality based on product name and sku with sort by price and pagination feature.
5. Print the category tree structure.


Next

Post a Comment

0Comments
Post a Comment (0)
To Top