Outline of the backend interface
- ACL resource used to allow or disallow access to the ticket listing
- Menu item linking to tickets listing the constroller action
- Route that maps to our admin controller
- layout XMLs that map to the ticket listing the controller action
- Controller action for listing tickets
- Full XML layout grid definition within layout XMLs defining grid, custom column renders, and custom dropdown filter values
- Controller action for closing ticket and send e-mails to customers
Creating Access Control Lists (acl.xml)
The app/code/Jeff/Helpdesk/etc/acl.xml file is where we define our module access control list resources.
#app/code/Jeff/Helpdesk/etc/acl.xml
Access control list resources are visible under the Magento admin System | Permission | User Role, as shown in the following screenshot:
Creating menu item linking to the tickets listing the controller acction.
#app/code/Jeff/Helpdesk/etc/adminhtml/menu.xml
The resource attribute references the ACL resource defined in the app/code/Jeff/Helpdesk/etc/acl.xml file.
Creating routes, controllers and layout hanldes
#app/code/Jeff/Helpdesk/etc/adminhtml/routes.xml
The admin route definition is almost identical to the frontend router defintion, where the differnce is for the router ID value.
With the router definition in place, we can now define our three layout XMLs, which map to the ticket listing the controller action:
- jeff_helpdesk_ticket_index.xml
- jeff_helpdesk_ticket_grid.xml
- jeff_helpdesk_ticket_grid_block.xml
jeff_helpdesk_ticket_index.xml
#app/code/Jeff/Helpdesk/view/adminhtml/layout/jeff_helpdesk_ticket_index.xml
Two update handles are specified. One pulls in formkey and the other pulls in jeff_helpdesk_ticket_grid_block.
jeff_helpdesk_ticket_grid.xml
#app/code/Jeff/Helpdesk/view/adminhtml/layout/jeff_helpdesk_ticket_grid.xml
jeff_helpdesk_ticket_grid_block.xml
#app/code/Jeff/Helpdesk/view/adminhtml/layout/jeff_helpdesk_ticket_grid_block.xml ticketGrid Jeff\Helpdesk\Model\ResourceModel\Ticket\Collection ticket_id desc true true ID number ticket_id ticket_id Title string title title Severity severity options Jeff\Helpdesk\Block\Adminhtml\Ticket\Grid\Renderer\Severity col-form_id col-form_id Status Status options Jeff\Helpdesk\Block\Adminhtml\Ticket\Grid\Renderer\Status col-form_id col-form_id action Action action getId false false - Close
- */*/close
- id
col-form_id col-form_id
Utilizing the grid widget: Ticket.php
#app/code/Jeff/Helpdesk/Block/Adminhtml/Ticket.php _controller = 'adminhtml'; $this->_blockGroup = 'Jeff_Helpdesk'; $this->_headerText = __('Tickets'); parent::_construct(); $this->removeButton('add'); } } /* Not much is happening in the Ticket Block class here. _controller and _blockGroup, as these serve as a sort of glue for telling our grid where to find other possible block classes. */
Two grid column renderers
Severity.php File:
#app/code/Jeff/Helpdesk/Block/Adminhtml/Ticket/Grid/Renderer/Severity.php ticketFactory = $ticketFactory; } public function render(\Magento\Framework\DataObject $row) { $ticket = $this->ticketFactory->create()->load($row->getId()); if($ticket && $ticket->getId()) { return $ticket->getSeverityAsLabel(); } return ''; } }
Status.php file:
#app/code/Jeff/Helpdesk/Block/Adminhtml/Ticket/Grid/Renderer/Status.php ticketFactory = $ticketFactory; } public function render(\Magento\Framework\DataObject $row) { $ticket = $this->ticketFactory->create()->load($row->getId()); if($ticket && $ticket->getId()) { return $ticket->getStatusAsLabel(); } return ''; } }
Creating controller actions
abstract class Ticket.php for all the adminhtml controllers to extend.
# app/code/Jeff/Helpdesk/Controller/Adminhtml/Ticket.php resultPageFactory = $resultPageFactory; $this->resultForwardFactory = $resultForwardFactory; $this->resultRedirectFactory = $context->getResultRedirectFactory(); parent::__construct($context); } protected function _isAllowed() { return $this->_authorization->isAllowed('Jeff_Helpdesk::ticket_manage'); } protected function _initAction() { $this->_view->loadLayout(); $this->_setActiveMenu('Jeff_Helpdesk::ticket_manage')->_addBreadcrumb(__('Helpdesk'), __('Tickets')); return $this; } } /* $resultPageFactory, $resultForwardFactory, $resultRedirectFactory are object to be used on the child. */
Index action:
#app/code/Jeff/Helpdesk/Controller/Adminhtml/Ticket/Index.php resultPageFactory->create(); if($this->getRequest()->getQuery('ajax')) { $resultForward = $this->resultForwardFactory->create(); $resultForward->forward('grid'); return $resultForward; } $resultPage = $this->resultPageFactory->create(); $resultPage->setActiveMenu('Jeff_Helpdesk::ticket_manage'); $resultPage->getConfig()->getTitle()->prepend(__('Tickets')); $resultPage->addBreadcrumb(__('Tickets'), __('Tickets')); $resultPage->addBreadcrumb(__('Manage Tickets'), __('Manage Tickets')); return $resultPage; } }
Grid action:
#app/code/Jeff/Helpdesk/Controller/Adminhtml/Ticket/Grid.php _view->loadLayout(false); $this->_view->renderLayout(); } } /* However, if we now try to use sorting or filtering, we would get a broken layout. This is because based on arguments defined under the jeff_helpdesk_ticket_grid_block.xml file, we are missing the controller Grid action. When we use sorting or filtering, the AJAX request hits the Index controller Grid Action. The code within thex execute method simplye calls the loadLayout(false) method to prevent the entire layout loading, making it load only the bits defined under the jeff_helpdesk_ticket_grid.xml fiel. */
Close action:
#app/code/Jeff/Helpdesk/Controller/Adminhtml/Ticket/Close.php ticketFactory = $ticketFactory; $this->customerRepository = $customerRepository; $this->transportBuilder = $transportBuilder; $this->inlineTranslation = $inlineTranslation; $this->scopeConfig = $scopeConfig; $this->storeManager = $storeManager; parent::__construct($context, $resultPageFactory, $resultForwardFactory); } public function execute() { $ticketId = $this->getRequest()->getParam('id'); $ticket = $this->ticketFactory->create()->load($ticketId); if($ticket && $ticket->getId()) { try{ $ticket->setStatus(\Jeff\Helpdesk\Model\Ticket::STATUS_CLOSED); $ticket->save(); $this->messageManager->addSuccess(__('Ticket successfully closed.')); // Send email to customer $this->messageManager->addSuccess(__('Customer notified via email')); } catch(Exception $e) { $this->messageManager->addError(__('Error with closing ticket action')); } } $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('*/*/index'); return $resultRedirect; } }
The Close action has two separate roles to fulfill. One is to change the ticket status; the other is to send an e-mail to the customer using the proper e-mail template
At this point, we should be able to see the screen, as shown in the following screenshot:
Summary
With this tutorial, “Helpdesk Tickets System”, we covered quite a lot of various Magento 2 platform parts, from routes, ACLs, controllers, blocks, XML layouts, grids, controller actions, models, resources, collections, install scripts, email templates, email transport, and layout.
You could download the code from Github
Enjoy!!!!