Controllers and actions
An action is a class that receives a request and returns a response. In Magento every URL has its own class with a single execute() method. The word "controller" here simply means a folder that holds related actions.
Where an action lives
The URL /hello/index/index leads to the module's Controller/Index/Index.php class. The file is created by hand.
app/code/Acme/Hello/
├── registration.php
├── Controller/
│ └── Index/
│ └── Index.php new file
└── etc/
├── module.xml
└── frontend/
└── routes.xmlA simple action
// app/code/Acme/Hello/Controller/Index/Index.php
namespace Acme\Hello\Controller\Index;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;
class Index implements HttpGetActionInterface
{
public function __construct(private ResultFactory $resultFactory) {}
public function execute(): ResultInterface
{
$result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
$result->setContents('Hello from the module!');
return $result;
}
}Open http://shop.test/hello — the browser shows the line "Hello from the module!" without the shop design. The HttpGetActionInterface interface lets the action answer only GET requests; for form submissions use HttpPostActionInterface. Magento passes the ResultFactory object into the constructor itself — the dependency injection lesson explains how.
Result types
The execute() method returns a result object. The type is set by a ResultFactory constant:
| Constant | What it returns |
|---|---|
TYPE_RAW | Arbitrary text |
TYPE_PAGE | A shop page with the header and the footer |
TYPE_JSON | Data in JSON format |
TYPE_REDIRECT | A redirect to another URL |
TYPE_FORWARD | Hands the request to another action |
A shop page
Replace the body of the execute() method:
$page = $this->resultFactory->create(ResultFactory::TYPE_PAGE);
$page->getConfig()->getTitle()->set(__('Greeting'));
return $page;The /hello URL now opens a regular shop page with the title "Greeting" and an empty middle. The layouts lesson shows how to fill it. The __() function makes a string translatable.
A JSON response and parameters
Create a second action — the Controller/Index/Status.php file:
// app/code/Acme/Hello/Controller/Index/Status.php
namespace Acme\Hello\Controller\Index;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;
class Status implements HttpGetActionInterface
{
public function __construct(
private ResultFactory $resultFactory,
private RequestInterface $request,
) {}
public function execute(): ResultInterface
{
$id = (int) $this->request->getParam('id');
return $this->resultFactory->create(ResultFactory::TYPE_JSON)
->setData(['status' => 'ok', 'id' => $id]);
}
}The URL /hello/index/status/id/5 returns {"status":"ok","id":5}. The getParam() method reads a parameter both from the URL path and from the query string; the second argument is a default value.
Redirect
return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('hello');The visitor lands on the /hello page. setPath() takes a path in the same form as getUrl().
Common mistake
The page returns 404 although the class is written. Check three things: the namespace matches the file path, the folder is called Controller in the singular, and the letter case of the folder and file names is exactly the same as in the class. On Windows a case mistake goes unnoticed, but on a Linux server the file will not be found.