Magento 2.4 became a perfect opportunity to proceed with backwards-incompatible changes that were waiting for years. When I was speaking at Magento Conferences about replacing inheritance with composition, I was not aware that I was going to be a part of this history. One such change was this Pull Request and its followup introduced by Vinai Kopp. Althought this change was very expected, these PRs were not merged.
At the begining of 2020 Vinai encouraged me to continue the work on Controllers decomposition using his contribution. With his continuous support and tremendous work of Lena Orobei - together we finally delivered one of the biggest architectural changes towards decomposition of Controllers.
As a Module developer, to implement a new Controller Action you only have to implement the \Magento\Framework\App\ActionInterface
.
The authentication mechanisms for Customers are also migrated!
Module developers don't have to extend from any class to create a fully functional action controller.
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\View\Result\PageFactory;
class MyController implements HttpGetActionInterface
{
/** @var PageFactory */
protected $resultPageFactory;
public function __construct(PageFactory $resultPageFactory)
{
$this->resultPageFactory = $resultPageFactory;
}
public function execute()
{
return $this->resultPageFactory->create();
}
}
You may have noticed that we use \Magento\Framework\App\Action\HttpGetActionInterface
. It is a method-specific Interface extending ActionInterface
. If you want to explicitly define what methods are going to be handled by the Controller, the most common interfaces are:
\Magento\Framework\App\Action\HttpDeleteActionInterface
\Magento\Framework\App\Action\HttpGetActionInterface
\Magento\Framework\App\Action\HttpPostActionInterface
\Magento\Framework\App\Action\HttpPutActionInterface
Please be aware that the HEAD
method is handled the same way that GET
is.
Keeping in mind that previously \Magento\Framework\App\Action\Context
was injected into Actions with a set of classes:
/**
* @param \Magento\Framework\App\RequestInterface $request
* @param \Magento\Framework\App\ResponseInterface $response
* @param \Magento\Framework\ObjectManagerInterface $objectManager
* @param \Magento\Framework\Event\ManagerInterface $eventManager
* @param \Magento\Framework\UrlInterface $url
* @param \Magento\Framework\App\Response\RedirectInterface $redirect
* @param \Magento\Framework\App\ActionFlag $actionFlag
* @param \Magento\Framework\App\ViewInterface $view
* @param \Magento\Framework\Message\ManagerInterface $messageManager
* @param \Magento\Framework\Controller\Result\RedirectFactory $resultRedirectFactory
* @param \Magento\Framework\Controller\ResultFactory $resultFactory
*/
There's no doubt that the new way of creating Controllers is much cleaner. The performance overhead caused by instantiating classes that are not used by the Controller is significally reduced.
Simple controllers like customer/account/logoutSuccess
experience a 5%
decrease in CPU time on generation.
Complex controllers like customer/section/load
experience a > 30%
decrease in CPU time on generation.
Common ones like catalog/category/view
experience a 10%
decrease in CPU time on generation.
Performance measurements were performed using BlackFire.io, in an isolated Docker environment with cURL requests, not being affected by Browser/Network overhead. Thanks to Christophe Dujarric for BlackFire's support.
Controllers are easier to test (due to their reduced amount of dependencies).
Inheritance of AbstractAction
forces you to use at least the same dependencies that the parent class has. Unit Test for Category View has more than 70 lines of mocking dependencies, mocking Context
methods to return mocked dependencies.
With the Composition approach you can inject dependencies directly to your class and inject only the ones you need (for example, only the ones you are going to use with your Unit Tests).
AbstractAction
. For example \Magento\Customer\Controller\AccountInterface
additionally handles Customer Authentication.\Magento\Backend\App\AbstractAction
, \Magento\Framework\App\Action\Action
, \Magento\Framework\App\Action\AbstractAction
, Magento\Framework\App\Action\Action\AbstractAccount
) and you should not use them anymore.getRequest
, getResponse
, getActionFlag
are eliminated with the inheritance and it will lead to errors when accessing them through controller object from event.You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.