Back to Top

Magento 2 Development 25: Helper

Updated 26 July 2024

One very important concept that is widely used in Magento is Helper. So here we will learn what is helper and how to use them.

It’s always a good idea to create all the functions which are used frequently in a single class. That’s why we use a helper to group all frequently used or common methods together. It helps in implementing the DRY concept in coding.

By grouping I mean we create different helper which takes care of different things if putting all the methods in a single class become too cumbersome. One such example of grouping that you frequently observe in Magento is a helper to handle all email-related tasks.

The helpers can be injected anywhere (i.e. in Blocks, Controllers, templates, etc) so that we can access the methods of that helper class. Injection of the class is just a fancy term for “mentioning the class in the constructor” so that we can create the object of that class.

In this blog, for now, I will only create a single function to get the customer id. We can not get the customer id from the session if all the caches are enabled. So we need to do some hacks, which we will do later.

Searching for an experienced
Magento 2 Company ?
Find out More

If you remember we have used the customer id in 3-4 places. And everywhere we have used the session to get it. Now if we have to implement the hack, we will have to update the code in 3-4 places. Which is not ideal.

So we will create a function in Helper to get the customer id. And we will call it everywhere else where the customer id is needed. So now we have to change only one function if we do some changes later. Note that we will and can keep adding more functions to the helper as we see fit.


Creating and Using the Helper

To create the helpers we use a new folder named Helper inside the module directory. By default, we create a helper with the name Data. But we can use any name. Let’s create the helper as Helper/Data.php

Code for Helper/Data.php file

<?php
namespace Webkul\BlogManager\Helper;

use Magento\Customer\Model\Session;

class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
    /**
     * @var Magento\Customer\Model\Session
     */
    protected $customerSession;
    
    /**
     * Dependency Initilization
     *
     * @param Session $customerSession
     * @param \Magento\Framework\App\Helper\Context $context
     */
    public function __construct(
        Session $customerSession,
        \Magento\Framework\App\Helper\Context $context
    ) {
        $this->customerSession = $customerSession;
        parent::__construct($context);
    }

    /**
     * Get Customer Id
     *
     * @return int
     */
    public function getCustomerId()
    {
        $customerId = $this->customerSession->getCustomerId();
        return $customerId;
    }
}

Since this is a helper, we have extended the default helper class. And we have created a method to get the customer id.

Now let’s quickly update all the codes where we have used the customer id. We will have to edit Block/BlogList.php

Updated code for Block/BlogList.php file

<?php
namespace Webkul\BlogManager\Block;

class BlogList extends \Magento\Framework\View\Element\Template
{
    /**
     * @var \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory
     */
    protected $blogCollection;

    /**
     * @var \Webkul\BlogManager\Helper\Data
     */
    protected $helper;

    /**
     * Dependency Initilization
     *
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollection
     * @param \Webkul\BlogManager\Helper\Data $helper
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollection,
        \Webkul\BlogManager\Helper\Data $helper,
        array $data = []
    ) {
        $this->blogCollection = $blogCollection;
        $this->helper = $helper;
        parent::__construct($context, $data);
    }

    /**
     * Get Blog List
     *
     * @return \Webkul\BlogManager\Model\ResourceModel\Blog\Collection
     */
    public function getBlogs()
    {
        $customerId = $this->helper->getCustomerId();
        $collection = $this->blogCollection->create();
        $collection->addFieldToFilter('user_id', ['eq'=>$customerId])->setOrder('updated_at', 'DESC');
        return $collection;
    }
}

As you can see here, we have removed the session codes. And injected the helper class in the constructor and called the getCustomerId function.

We also have to edit the Controller/Manage/Edit.php

Updated code for Controller/Manage/Edit.php file

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

use Magento\Customer\Controller\AbstractAccount;
use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;

class Edit extends AbstractAccount
{
    /**
     * @var Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;

    /**
     * @var \Webkul\BlogManager\Model\BlogFactory
     */
    protected $blogFactory;

    /**
     * @var \Webkul\BlogManager\Helper\Data
     */
    protected $helper;

    /**
     * @var \Magento\Framework\Message\ManagerInterface
     */
    protected $messageManager;

    /**
     * Dependency Initilization
     *
     * @param Context $context
     * @param PageFactory $resultPageFactory
     * @param \Webkul\BlogManager\Model\BlogFactory $blogFactory
     * @param \Webkul\BlogManager\Helper\Data $helper
     * @param \Magento\Framework\Message\ManagerInterface $messageManager
     */
    public function __construct(
        Context $context,
	    PageFactory $resultPageFactory,
        \Webkul\BlogManager\Model\BlogFactory $blogFactory,
        \Webkul\BlogManager\Helper\Data $helper,
        \Magento\Framework\Message\ManagerInterface $messageManager
    ) {
	    $this->resultPageFactory = $resultPageFactory;
	    $this->blogFactory = $blogFactory;
	    $this->helper = $helper;
	    $this->messageManager = $messageManager;
        parent::__construct($context);
    }

    /**
     * Provides content
     *
     * @return Magento\Framework\View\Result\Page
     * @return Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        $blogId = $this->getRequest()->getParam('id');
        $customerId = $this->helper->getCustomerId();
        $isAuthorised = $this->blogFactory->create()
                                    ->getCollection()
                                    ->addFieldToFilter('user_id', $customerId)
                                    ->addFieldToFilter('entity_id', $blogId)
                                    ->getSize();
        if (!$isAuthorised) {
            $this->messageManager->addError(__('You are not authorised to edit this blog.'));
            return $this->resultRedirectFactory->create()->setPath('blog/manage');
        }

        $resultPage = $this->resultPageFactory->create();
        $resultPage->getConfig()->getTitle()->set(__('Edit Blog'));
        $layout = $resultPage->getLayout();
        return $resultPage;
    }
}

And also Controller/Manage/Save.php

Updated code for Controller/Manage/Save.php file

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

use Magento\Customer\Controller\AbstractAccount;
use Magento\Framework\App\Action\Context;

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

    /**
     * @var \Webkul\BlogManager\Helper\Data
     */
    protected $helper;

    /**
     * @var \Magento\Framework\Message\ManagerInterface
     */
    protected $messageManager;

    /**
     * Dependency Initilization
     *
     * @param Context $context
     * @param \Webkul\BlogManager\Model\BlogFactory $blogFactory
     * @param \Webkul\BlogManager\Helper\Data $helper
     * @param \Magento\Framework\Message\ManagerInterface $messageManager
     */
    public function __construct(
        Context $context,
        \Webkul\BlogManager\Model\BlogFactory $blogFactory,
        \Webkul\BlogManager\Helper\Data $helper,
        \Magento\Framework\Message\ManagerInterface $messageManager
    ) {
        $this->blogFactory = $blogFactory;
        $this->helper = $helper;
        $this->messageManager = $messageManager;
        parent::__construct($context);
    }

    /**
     * Provides content
     *
     * @return Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        $data = $this->getRequest()->getParams();
        $customerId = $this->helper->getCustomerId();
        if (isset($data['id']) && $data['id']) {
            $isAuthorised = $this->blogFactory->create()
                                        ->getCollection()
                                        ->addFieldToFilter('user_id', $customerId)
                                        ->addFieldToFilter('entity_id', $data['id'])
                                        ->getSize();
            if (!$isAuthorised) {
                $this->messageManager->addError(__('You are not authorised to edit this blog.'));
                return $this->resultRedirectFactory->create()->setPath('blog/manage');
            } else {
                $model = $this->blogFactory->create()->load($data['id']);
                $model->setTitle($data['title'])
                    ->setContent($data['content'])
                    ->save();
                $this->messageManager->addSuccess(__('You have updated the blog successfully.'));
            }
        } else {
            $model = $this->blogFactory->create();
            $model->setData($data);
            $model->setUserId($customerId);
            $model->save();
            $this->messageManager->addSuccess(__('Blog saved successfully.'));
        }        
        return $this->resultRedirectFactory->create()->setPath('blog/manage');
    }
}

One more file that we have to edit is Controller/Manage/Delete.php

Updated code for Controller/Manage/Delete.php file

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

use Magento\Customer\Controller\AbstractAccount;
use Magento\Framework\App\Action\Context;

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

    /**
     * @var \Webkul\BlogManager\Helper\Data
     */
    protected $helper;

    /**
     * @var \Magento\Framework\Serialize\Serializer\Json
     */
    protected $jsonData;

    /**
     * Dependency Initilization
     *
     * @param Context $context
     * @param \Webkul\BlogManager\Model\BlogFactory $blogFactory
     * @param \Webkul\BlogManager\Helper\Data $helper
     * @param \Magento\Framework\Serialize\Serializer\Json $jsonData
     */
    public function __construct(
        Context $context,
        \Webkul\BlogManager\Model\BlogFactory $blogFactory,
        \Webkul\BlogManager\Helper\Data $helper,
        \Magento\Framework\Serialize\Serializer\Json $jsonData
    ) {
        $this->blogFactory = $blogFactory;
        $this->helper = $helper;
        $this->jsonData = $jsonData;
        parent::__construct($context);
    }

    /**
     * Provides content
     *
     * @return Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        $blogId = $this->getRequest()->getParam('id');
        $customerId = $this->helper->getCustomerId();
        $isAuthorised = $this->blogFactory->create()
                                    ->getCollection()
                                    ->addFieldToFilter('user_id', $customerId)
                                    ->addFieldToFilter('entity_id', $blogId)
                                    ->getSize();
        if (!$isAuthorised) {
            $msg=__('You are not authorised to delete this blog.');
            $success=0;
        } else {
            $model = $this->blogFactory->create()->load($blogId);
            $model->delete();
            $msg=__('You have successfully deleted the blog.');
            $success=1;
        }     
        $this->getResponse()->setHeader('Content-type', 'application/javascript');
        $this->getResponse()->setBody(
            $this->jsonData->serialize(
                    [
                        'success' => $success,
                        'message' => $msg
                    ]
                ));
    }
}

Now we have created and used a helper. Please verify all the pages that these changes affect. And please make a habit of checking/verifying the changes even if it’s a minor change.

Cacheable

One more thing that I missed earlier is the use of a cacheable argument. By default, Magento cached all pages. So if you enable all caches and check the blog listing page you will see some confusing results.

Magento recommends that all public pages (pages that can be accessed without sign-in) must be cacheable. That means all pages such as the category page, product page, and cms page are cached.

And it makes sense because the public pages are get frequently accessed and the data on those pages do not change based on who the user is.

However, for all non-public pages (those pages which can be accessed only after logging in), we should disable the cache if the data is not static for that page.

We have not yet created any public page, we will do in the next blogs. So in our case, the private pages are blog listing, blog edit page, and blog add page.

We do not care blog add page because it is static we just show a blank form. But for the other two pages, we will have to disable the cache. Which we can do from the layout xml file.

So let’s first edit the view/frontend/layout/blogmanager_manage_index.xml

Updated code for view/frontend/layout/blogmanager_manage_index.xml file

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="customer_account"/>
    <body>
        <referenceContainer name="content">
            <block class="Webkul\BlogManager\Block\BlogList" name="blogmanager.blog.list" template="Webkul_BlogManager::list.phtml" cacheable="false" />
        </referenceContainer>
    </body>
</page>

Here we have done a very minor change. We have just added cacheable=”false” in the node.

Now this page won’t be cached. Note that if there were multiple blocks then adding cacheable=”false” in any one of them will make the whole page non-cacheable. That means we can not say that cache this block and not this in a page.


Let’s edit the other pages also view/frontend/layout/blogmanager_manage_edit.xml

Updated code for view/frontend/layout/blogmanager_manage_edit.xml file

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="customer_account"/>
    <head>
		<css src="Webkul_BlogManager::css/style.css"/>
	</head>
    <body>
        <referenceContainer name="content">
            <block class="Webkul\BlogManager\Block\Blog" name="blogmanager.blog.edit" template="Webkul_BlogManager::edit.phtml" cacheable="false" />
        </referenceContainer>
    </body>
</page>

Now it will work fine even if we enable all caches.

Show Few More Columns

It is not related to the previous topics. But it is a minor change so I will append it to this blog. As you can see there are various important details are missing from the blog list on the seller side. We will do some changes to show the status, created at, and updated at on the grid.

First, we will edit the phtml file view/frontend/templates/list.phtml

Updated code for view/frontend/templates/list.phtml file

<div class="blog-list-table-container">
    <table class="blog-list-table">
        <tr class="blog-list-table-head">
            <th class="blog-list-table-id">
                <?= __("Id")?>
            </th>
            <th class="blog-list-table-title">
                <?= __("Title")?>
            </th>
            <th class="blog-list-table-content">
                <?= __("Content")?>
            </th>
            <th class="blog-list-table-status">
                <?= __("Status")?>
            </th>
            <th class="blog-list-table-date">
                <?= __("Updated At")?>
            </th>
            <th class="blog-list-table-date">
                <?= __("Created At")?>
            </th>
            <th class="blog-list-table-action-edit">
                <?= __("Edit")?>
            </th>
            <th class="blog-list-table-action-delete">
                <?= __("Delete")?>
            </th>
        </tr>
        <?php
        $blogs = $block->getBlogs();
        $statuses = $escaper->escapeHtml($block->getStatuses());
        foreach ($blogs as $blog) {?>
        <tr class="blog-list-table-row">
            <td class="blog-list-table-id">
                <?= $escaper->escapeHtml($blog->getId())?>
            </td>
            <td class="blog-list-table-title">
                <?= $escaper->escapeHtml($blog->getTitle())?>
            </td>
            <td class="blog-list-table-content">
                <?= substr($escaper->escapeHtml($blog->getContent()), 0, 20).'...'?>
            </td>
            <td class="blog-list-table-status">
                <?= $escaper->escapeHtml($statuses[$escaper->escapeHtml($blog->getStatus())])?>
            </td>
            <td class="blog-list-table-date">
                <?= $escaper->escapeHtml($block->getFormattedDate($escaper->escapeHtml($blog->getUpdatedAt())))?>
            </td>
            <td class="blog-list-table-date">
                <?= $escaper->escapeHtml($block->getFormattedDate($escaper->escapeHtml($blog->getCreatedAt())))?>
            </td>
            <td class="blog-list-table-action blog-list-table-action-edit">
                <a href="<?= $escaper->escapeUrl($block->getUrl('blog/manage/edit', ['id'=>$blog->getId()]))?>">
                    <?= __('Edit') ?>
                </a>
            </td>
            <td class="blog-list-table-action blog-list-table-action-delete">
                <a href="<?= $escaper->escapeUrl($block->getUrl('blog/manage/delete', ['id'=>$blog->getId()]))?>">
                    <?= __('Delete') ?>
                </a>
            </td>
        </tr>
        <?php } ?>
    </table>
</div>
<script type="text/x-magento-init">
    {
        "*": {
            "bloglist": ""
        }
    }
</script>

In the head section of the table, we have added the three columns, and similarly in the body section also.

We have called a method getStatuses which will return an associative array with an integer (0 or 1) as the key and the status label as the value. Using this we can show the label based on the value.

One more thing is that we are not showing the Date directly from the database. We have created the getFormattedDate function in the block class which will format the date in a nice readable format.

Now let’s create these methods in Block/BlogList.php

Updated code for Block/BlogList.php file

<?php
namespace Webkul\BlogManager\Block;

class BlogList extends \Magento\Framework\View\Element\Template
{
    /**
     * @var \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory
     */
    protected $blogCollection;

    /**
     * @var \Webkul\BlogManager\Helper\Data
     */
    protected $helper;

    /**
     * @var \Webkul\BlogManager\Model\Blog\Status
     */
    protected $blogStatus;

    /**
     * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
     */
    protected $date;

    /**
     * Dependency Initilization
     *
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollection
     * @param \Webkul\BlogManager\Helper\Data $helper
     * @param \Webkul\BlogManager\Model\Blog\Status $blogStatus
     * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $date
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollection,
        \Webkul\BlogManager\Helper\Data $helper,
        \Webkul\BlogManager\Model\Blog\Status $blogStatus,
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $date,
        array $data = []
    ) {
        $this->blogCollection = $blogCollection;
        $this->helper = $helper;
        $this->blogStatus = $blogStatus;
        $this->date = $date;
        parent::__construct($context, $data);
    }

    /**
     * Get Blog List
     *
     * @return \Webkul\BlogManager\Model\ResourceModel\Blog\Collection
     */
    public function getBlogs()
    {
        $customerId = $this->helper->getCustomerId();
        $collection = $this->blogCollection->create();
        $collection->addFieldToFilter('user_id', ['eq'=>$customerId])->setOrder('updated_at', 'DESC');
        return $collection;
    }

    /**
     * Get Blog Status
     *
     * @return boolean
     */
    public function getStatuses()
    {
        $statuses = [];
        foreach ($this->blogStatus->toOptionArray() as $status) {
            $statuses[$status['value']] = $status['label'];
        }
        return $statuses;
    }

    /**
     * Get Formatted Date
     *
     * @param date $date
     * @return date
     */
    public function getFormattedDate($date)
    {
        return $this->date->date($date)->format('d/m/y H:i');
    }
}

In getStatuses, we have used the class that we created to get the statuses for the UI component. It is a good practice because if we want to add more statuses then we will have to change only in one file.

To get the formatted date we have used \Magento\Framework\Stdlib\DateTime\TimezoneInterface which will return the date in the mentioned format.

If we want to convert then we have to pass the timestamp in date() and if we leave it empty then the current timestamp will be used. Note that this will return the date based on the locale.

Now you will see all the details like,

2021-08-03_10-36


Next Blog -> Magento 2 Development 26: Blog Listing

Previous Blog -> Magento 2 Development 24: Loading Magento’s Data

. . .

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