Magento works on the LEMP stack, which consists of:
- Linux: The OS that offers security and supports PHP.
- NGINX: The web server that accepts incoming requests and forwards them to various stacks, notably PHP. It provides high performance and low memory usage.
- MySQL: Used for database management.
- PHP: A widely used programming language for backend development.
Other components include XML, Elasticsearch, and Redis.
The most important directories in any Magento project are:
app/
– Contains custom modules and themes that you will build.pub/
– Known as the web root, this is where the web server points. The entry point for web requests in Magento ispub/index.php
.var/
– Stores generated data such as cache files, logs, and session files.vendor/
– Contains all third-party modules, including Magento core. You should avoid placing files here for long-term use, as this directory may be rebuilt from scratch multiple times.
- PHPStorm – The IDE recommended for Magento development.
- Plugins – Magento PHPStorm, Xdebug.
Every Magento URL consists of three parts:
/<frontName>/<controllerName>/<actionName>
Let's break it down:
- Front Name: The start of the request, associated with a specific module.
- Controller Name: Determines the class handling the request.
- Action Name: Specifies the method responsible for processing the request.
Routes in Magento are defined using XML. Magento has two main areas:
frontend
– Handles the storefront.adminhtml
– Handles the admin panel.
To create a frontend route, navigate to:
app/code/Macademy/Jumpstart/etc/frontend/
Create a new file named routes.xml
with the following format:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="jumpstart" frontName="jumpstart">
<module name="Macademy_Jumpstart"/>
</route>
</router>
</config>
This ensures that Magento listens to requests at /jumpstart
.
The Controller Name corresponds to a class in the Controller
folder of your module.
-
Create a new directory for your module's controller:
app/code/Macademy/Jumpstart/Controller/
-
Inside this directory, create a subdirectory named after the controller name:
app/code/Macademy/Jumpstart/Controller/Index/
-
Create the Action Class inside the
Index
folder:app/code/Macademy/Jumpstart/Controller/Index/Index.php
Dependency Injection (DI) is a way to manage class dependencies and make code more modular and testable.
A PHP class can rely on other classes using the new
keyword:
<?php
declare(strict_types=1);
namespace Macademy\Jumpstart\Model;
class Product
{
private Category $category;
public function __construct()
{
$this->category = new Category();
}
public function getCategoryName(): string
{
return $this->category->getName();
}
}
However, using new
creates tightly coupled code, making it harder to test and modify.
Instead of manually instantiating objects, Magento uses ObjectManager, which:
- Centralizes object creation.
- Allows for dependency injection.
- Increases flexibility and testability.
Since Magento 2.4.4+ supports PHP 8, we can use constructor property promotion to simplify our code.
<?php
declare(strict_types=1);
namespace Macademy\Jumpstart\Model;
class Product
{
private Category $category;
public function __construct(Category $category)
{
$this->category = $category;
}
public function getCategoryName(): string
{
return $this->category->getName();
}
}
<?php
declare(strict_types=1);
namespace Macademy\Jumpstart\Model;
class Product
{
public function __construct(private Category $category) {}
public function getCategoryName(): string
{
return $this->category->getName();
}
}
This reduces boilerplate code while maintaining the same functionality.
An interface defines a contract for a class, enforcing method consistency across different implementations.
Instead of relying directly on the Category
class, we define an interface:
<?php
declare(strict_types=1);
namespace Macademy\Jumpstart\Api;
interface CategoryInterface
{
public function getName(): string;
}
Now, any class implementing this interface must define the getName()
method.
Magento uses dependency injection configuration (di.xml) to specify class preferences.
Example di.xml
configuration:
<preference for="Macademy\Jumpstart\Api\CategoryInterface"
type="Macademy\Jumpstart\Model\Category"/>
- Promotes loose coupling between modules.
- Makes replacing implementations easier.
- Allows for future flexibility (e.g., switching data sources without breaking code).
Instead of terminating execution with echo
, Magento provides a layout system for rendering pages.
To generate a page response, we inject PageFactory
into our controller:
<?php
declare(strict_types=1);
namespace Macademy\Jumpstart\Controller\Index;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\View\Result\Page;
class Index implements HttpGetActionInterface
{
private PageFactory $pageFactory;
public function __construct(PageFactory $pageFactory)
{
$this->pageFactory = $pageFactory;
}
public function execute(): Page
{
return $this->pageFactory->create();
}
}
This ensures that our controller returns a properly structured Magento page.