Skip to content
intermediate Phase 33 · Controllers

Controllers Deep Dive

AbstractAction, ActionInterface, HTTP vs non-action controllers, and controller architecture.

45m
0 problems
Topic Progress 0%

Controller Class Hierarchy

Magento controllers follow a specific class hierarchy.

Class hierarchy:

ActionInterface
└── AbstractAction (Magento\Framework\App\Action\AbstractAction)
    ├── Action (Magento\Framework\App\Action\Action) — Frontend
    └── Backend\App\Action (Magento\Backend\App\Action) — Admin
        └── Backend\App\Action\AbstractMassAction

Frontend controller:

<?php
namespace Vendor\Blog\Controller\Post;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

class View extends Action
{
    public function __construct(
        Context $context,
        private \Vendor\Blog\Model\PostFactory $postFactory
    ) {
        parent::__construct($context);
    }
    
    public function execute()
    {
        $id = $this->getRequest()->getParam('id');
        $post = $this->postFactory->create()->load($id);
        
        if (!$post->getId()) {
            $this->messageManager->addErrorMessage(__('Post not found'));
            return $this->_redirect('*/*/index');
        }
        
        $this->_view->getLayout()->registerScript(
            'Vendor_Blog::post/view.phtml'
        );
        $this->_view->renderPage();
    }
}

Admin controller:

<?php
namespace Vendor\Blog\Controller\Adminhtml\Post;

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

class Edit extends Action
{
    const ADMIN_RESOURCE = 'Vendor_Blog::blog_posts';
    
    public function __construct(
        Context $context,
        private \Magento\Backend\Model\View\ResultPageFactory $resultPageFactory
    ) {
        parent::__construct($context);
    }
    
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
        $resultPage->getConfig()->getTitle()->set(__('Edit Post'));
        
        return $resultPage;
    }
}

Frontend vs Admin Controllers

Frontend and admin controllers have different base classes and capabilities.

Frontend controller features:

  • Extends Action (Magento\Framework\App\Action\Action)
  • Access to _view for layout rendering
  • Session and cookie management
  • Customer authentication optional
  • Area: frontend

Admin controller features:

  • Extends Backend\App\Action
  • ACL permission checking via ADMIN_RESOURCE
  • Admin session authentication required
  • Access to admin UI components
  • Area: adminhtml

Comparison:

// Frontend\Action has:
$this->_view              // View factory
$this->_redirect()        // Redirect helper
$this->messageManager     // Session messages
$this->getRequest()       // Request object
$this->getResponse()      // Response object

// Backend\App\Action has everything above plus:
$this->_auth              // Admin auth
$this->_authorization     // ACL checking
$this->_adminSession      // Admin session
$this->_backendUrl        // Admin URL builder

Non-action controllers:

// Controllers that don't follow standard action pattern
// Used for: APIs, exports, imports, special handlers

<?php
namespace Vendor\Module\Controller;

use Magento\Framework\App\Action\Action;

class Export extends Action
{
    public function execute()
    {
        // Set response headers
        $this->getResponse()->setHeader('Content-Type', 'text/csv');
        $this->getResponse()->setHeader('Content-Disposition', 'attachment; filename="export.csv"');
        
        // Output directly
        $this->getResponse()->setBody($csvContent);
        
        return $this->getResponse();
    }
}

AbstractAction and Shared Logic

AbstractAction provides common functionality for all controllers.

What AbstractAction provides:

// In your controller constructor
public function __construct(
    Context $context  // Required: includes all shared dependencies
) {
    parent::__construct($context);
}

// Context provides:
// - $this->_view (View)
// - $this->messageManager (ManagerInterface)
// - $this->_redirect (RedirectInterface)
// - $this->getRequest() (RequestInterface)
// - $this->getResponse() (ResponseInterface)
// - $this->_eventManager (EventManager)
// - $this->_storeManager (StoreManagerInterface)
// - $this->_logLogger (Logger)

Creating base controller for shared logic:

<?php
namespace Vendor\Blog\Controller;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

class AbstractPost extends Action
{
    public function __construct(
        Context $context,
        protected \Vendor\Blog\Model\PostFactory $postFactory,
        protected \Vendor\Blog\Service\PostService $postService
    ) {
        parent::__construct($context);
    }
    
    protected function getPost(): ?\Vendor\Blog\Model\Post
    {
        $id = $this->getRequest()->getParam('id');
        if (!$id) {
            return null;
        }
        
        $post = $this->postFactory->create()->load($id);
        return $post->getId() ? $post : null;
    }
    
    protected function validatePost(\Vendor\Blog\Model\Post $post): bool
    {
        if (!$post->getTitle()) {
            $this->messageManager->addErrorMessage(__('Title is required'));
            return false;
        }
        return true;
    }
}

// Use in controller
class Save extends AbstractPost
{
    public function execute()
    {
        $post = $this->getPost();
        // ...
    }
}

Controller Best Practices

Best practices for controller implementation.

1. Keep controllers thin:

// BAD: Business logic in controller
class Save extends Action
{
    public function execute()
    {
        // 100+ lines of business logic
    }
}

// GOOD: Delegate to service class
class Save extends Action
{
    public function __construct(
        Context $context,
        private \Vendor\Module\Service\SaveService $saveService
    ) {
        parent::__construct($context);
    }
    
    public function execute()
    {
        try {
            $this->saveService->save($this->getRequest()->getParams());
            $this->messageManager->addSuccessMessage(__('Saved successfully'));
        } catch (\Exception $e) {
            $this->messageManager->addErrorMessage($e->getMessage());
        }
        
        return $this->_redirect('*/*/index');
    }
}

2. Always return ResultInterface:

// Return types:
return $this->resultFactory->create(
    \Magento\Framework\View\Result\Page::class
); // Page result

return $this->resultRedirectFactory->create()
    ->setPath('*/*/index'); // Redirect result

return $this->resultFactory->create(
    \Magento\Framework\Controller\Result\Json::class
)->setData($data); // JSON result

3. Use proper HTTP methods:

// GET: Read operations
class View extends Action { /* ... */ }

// POST: Write operations
class Save extends Action { /* ... */ }

// DELETE: Delete operations
class Delete extends Action { /* ... */ }

4. Handle errors gracefully:

public function execute()
{
    try {
        // Process
        $this->messageManager->addSuccessMessage(__('Success'));
    } catch (\Magento\Framework\Exception\LocalizedException $e) {
        $this->messageManager->addErrorMessage($e->getMessage());
    } catch (\Exception $e) {
        $this->messageManager->addErrorMessage(__('An error occurred'));
        $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
    }
    
    return $this->_redirect('*/*/index');
}

Quiz

1. What class do frontend controllers extend?

Question 1 options

2. What constant defines admin resource in admin controllers?

Question 2 options

3. What provides common dependencies to all controllers?

Question 3 options

4. What should controllers return?

Question 4 options

Flashcards

Question

What class do frontend controllers extend?

Answer

Magento\Framework\App\Action\Action

Question

What class do admin controllers extend?

Answer

Magento\Backend\App\Action

Question

What does ADMIN_RESOURCE define?

Answer

The ACL resource required for admin controller access

Question

What provides shared controller dependencies?

Answer

Magento\Framework\App\Action\Context

Question

What result types are available?

Answer

Page, Json, Redirect, Raw, Forward

Revision Notes

Key Takeaways

  • 1. Frontend controllers extend Action; admin controllers extend Backend\App\Action
  • 2. Context provides shared dependencies to all controllers
  • 3. ADMIN_RESOURCE constant controls admin ACL permissions
  • 4. Controllers should be thin — delegate business logic to services
  • 5. Always return ResultInterface (Page, Json, Redirect)
  • 6. Handle exceptions with messageManager

Interview Tips

  • Explain the difference between frontend and admin controllers
  • Describe the controller class hierarchy
  • Know how to implement shared logic in base controllers
  • Discuss error handling patterns in controllers

Cheat Sheet

Controllers Cheat Sheet

Frontend: extends Action
Admin: extends Backend\App\Action

Context provides:

  • messageManager
  • _redirect
  • _view
  • getRequest/getResponse
  • _eventManager

ADMIN_RESOURCE:

const ADMIN_RESOURCE = 'Vendor_Module::resource';

Return types:

  • Page (view)
  • Json (API)
  • Redirect (redirect)
  • Forward (internal forward)

Keep controllers thin → delegate to services