Table of Contents for
Magento 2 Development Quick Start Guide

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Magento 2 Development Quick Start Guide by Branko Ajzele Published by Packt Publishing, 2018
  1. Magento 2 Development Quick Start Guide
  2. Title Page
  3. Copyright and Credits
  4. Magento 2 Development Quick Start Guide
  5. Packt Upsell
  6. Why subscribe?
  7. Packt.com
  8. Contributors
  9. About the author
  10. About the reviewer
  11. Packt is searching for authors like you
  12. Table of Contents
  13. Preface
  14. Who this book is for
  15. What this book covers
  16. To get the most out of this book
  17. Download the example code files
  18. Code in Action
  19. Conventions used
  20. Get in touch
  21. Reviews
  22. Understanding the Magento Architecture
  23. Technical requirements
  24. Installing Magento
  25. Modes
  26. Areas
  27. Request flow processing
  28. Modules
  29. Creating the minimal module
  30. Cache
  31. Dependency injection
  32. Argument injection
  33. Virtual types
  34. Proxies
  35. Factories
  36. Plugins
  37. The before plugin
  38. The around plugin
  39. The after plugin
  40. Events and observers
  41. Console commands
  42. Cron jobs
  43. Summary
  44. Working with Entities
  45. Technical requirements
  46. Understanding types of models
  47. Creating a simple model
  48. Methods worth memorizing
  49. Working with setup scripts
  50. The InstallSchema script
  51. The UpgradeSchema script
  52. The Recurring script
  53. The InstallData script
  54. The UpgradeData script
  55. The RecurringData script
  56. Extending entities
  57. Creating extension attributes
  58. Summary
  59. Understanding Web APIs
  60. Technical requirements
  61. Types of users
  62. Types of authentication
  63. Types of APIs
  64. Using existing web APIs
  65. Creating custom web APIs
  66. Understanding search criteria
  67. Summary
  68. Building and Distributing Extensions
  69. Technical requirements
  70. Building a shipping extension
  71. Distributing via GitHub
  72. Distributing via Packagist
  73. Summary
  74. Developing for Admin
  75. Technical requirements
  76. Using the listing component
  77. Using the form component
  78. Summary
  79. Developing for Storefront
  80. Technical requirements
  81. Setting up the playground
  82. Calling and initializing JS components
  83. Meet RequireJS
  84. Replacing jQuery widget components
  85. Extending jQuery widget components
  86. Creating jQuery widgets components
  87. Creating UI/KnockoutJS components
  88. Extending UI/KnockoutJS components
  89. Summary
  90. Customizing Catalog Behavior
  91. Technical requirements
  92. Creating the size guide
  93. Creating the same day delivery
  94. Flagging new products
  95. Summary
  96. Customizing Checkout Experiences
  97. Technical requirements
  98. Passing data to the checkout
  99. Adding order notes to the checkout
  100. Summary
  101. Customizing Customer Interactions
  102. Technical requirements
  103. Understanding the section mechanism
  104. Adding contact preferences to customer accounts
  105. Adding contact preferences to the checkout
  106. Summary
  107. Other Books You May Enjoy
  108. Leave a review - let other readers know what you think

Request flow processing

URLs in Magento have the format of <AreaFrontName>/<VendorName>/<ModuleName>/<ControllerName>/<ActionName>, but this does not mean that we actually use the area, vendor, or module name in the URL any time we wish to access a certain controller. For example, the area for a request is defined by the first request path segment, such as admin for adminhtml area, and none for frontend area.

We use the router class to assign a URL to a corresponding controller and its action. The router's match method finds a matching controller, which is determined by an incoming request.

Conceptually, creating a new router is as simple as doing the following:

  1. Inject the new item under the routerList argument of the Magento\Framework\App\RouterList type via the di.xml file.
  2. Create a router file (by using the match method, which implements \Magento\Framework\App\RouterInterface).
  3. Return an instance of \Magento\Framework\App\ActionInterface.

By doing a lookup for the name="routerList" string across all of the <MAGENTO_DIR> di.xml files, we can see the following router definitions:

  • Magento\Robots\Controller\Router (robots)
  • Magento\Cms\Controller\Router (cms)
  • Magento\UrlRewrite\Controller\Router (urlrewrite)
  • Magento\Framework\App\Router\Base (standard)
  • Magento\Framework\App\Router\DefaultRouter (default)
  • Magento\Backend\App\Router (admin)

Let's take a closer look at the robots router under <MAGENTO_DIR>/module-robots. etc/frontend/di.xml injects the new item under the routerList argument as follows:

<type name="Magento\Framework\App\RouterList">
<arguments>
<argument name="routerList" xsi:type="array">
<item name="robots" xsi:type="array">
<item name="class" xsi:type="string">Magento\Robots\Controller\Router</item>
<item name="disable" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="string">10</item>
</item>
</argument>
</arguments>
</type>

The Magento\Robots\Controller\Router class has been further defined as per the following partial extract:

class Router implements \Magento\Framework\App\RouterInterface {
// Magento\Framework\App\ActionFactory
private $actionFactory;
// Magento\Framework\App\Router\ActionList
private $actionList;
// Magento\Framework\App\Route\ConfigInterface
private $routeConfig;

public function match(\Magento\Framework\App\RequestInterface $request) {
$identifier = trim($request->getPathInfo(), '/');
if ($identifier !== 'robots.txt') {
return null;
}

$modules = $this->routeConfig->getModulesByFrontName('robots');
if (empty($modules)) {
return null;
}

$actionClassName = $this->actionList->get($modules[0], null, 'index', 'index');
$actionInstance = $this->actionFactory->create($actionClassName);
return $actionInstance;
}
}

The match method checks if the robots.txt file was requested and returns the instance of the matched \Magento\Framework\App\ActionInterface type. By following this simple implementation, we can easily create the route of our own.

Conceptually, creating a new controller is as simple as doing the following:

  1. Register a route via router.xml.
  2. Create an abstract controller file (as an abstract class, which extends \Magento\Framework\App\Action\Action).
  1. Create an action controller file (which extends the main controller file with the execute method, and implements \Magento\Framework\App\ActionInterface).
  2. Return an instance of \Magento\Framework\Controller\ResultInterface.
The separation of the controller into the main and action controller files is not a technical requirement, but rather a recommended organizational one. Magento does this across the majority of its modules.

By doing a lookup for the <route string across the <MAGENTO_DIR> routes.xml files, we can see that Magento uses hundreds of route definitions, which are spread across its modules. Each route represents one controller.

Let's take a closer look at one of Magento's controllers, <MAGENTO_DIR>/module-customer, which maps to the http://magelicious.loc/customer/address/form URL. The route itself is registered via frontend/di.xml under the standard router with a customer ID and a customer frontName, as follows:

<router id="standard">
<route id="customer" frontName="customer">
<module name="Magento_Customer" />
</route>
</router>

The abstract controller file Controller/Address.php is defined partially as follows:

abstract class Address extends \Magento\Framework\App\Action\Action {
// The rest of the code...
}

The abstract controller is where we want to add functionality and dependencies that are shared across all of the child action controllers.

We can further see three different action controllers defined within the subdirectory which has the same name as the abstract class. The Controller/Address directory contains six action controllers: Delete.php, Edit.php, Form.php, FormPost.php, Index.php, and NewAction.php. Let's take a closer look at the following partial Form.php file's content:

class Form extends \Magento\Customer\Controller\Address {
public function execute() {
/** @var \Magento\Framework\View\Result\Page $resultPage */
$resultPage = $this->resultPageFactory->create();
$navigationBlock = $resultPage->getLayout()->getBlock('customer_account_navigation');
if ($navigationBlock) {
$navigationBlock->setActive('customer/address');
}
return $resultPage;
}
}

The example here uses the create method of the injected Magento\Framework\View\Result\PageFactory type to create a new page result. The various types of controller results can be found within the <MAGENTO_DIR>/framework directory:

  • Magento\Framework\Controller\Result\Json
  • Magento\Framework\Controller\Result\Raw
  • Magento\Framework\Controller\Result\Redirect
  • Magento\Framework\Controller\Result\Forward
  • Magento\Framework\View\Result\Layout
  • Magento\Framework\View\Result\Page

We can take the unified way of creating result instances by using the create method of \Magento\Framework\Controller\ResultFactory. The ResultFactory defines the TYPE_* constant for each of the mentioned controller result types:

const TYPE_JSON = 'json';
const TYPE_RAW = 'raw';
const TYPE_REDIRECT = 'redirect';
const TYPE_FORWARD = 'forward';
const TYPE_LAYOUT = 'layout';
const TYPE_PAGE = 'page';

Keeping these constants in mind, we can easily write our action controller code as follows:

$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
$resultRedirect->setPath('adminhtml/*/index');
return $resultRedirect;
A quick lookup for the $this->resultFactory-> create string, across the entire <MAGENTO_DIR> directory, can give us lots of examples of how to use the ResultFactory for our own code.