A collection of notes for the Magento 2 certified developer exams.
The exam includes questions relating to Magento Admin - more than you would expect. It is worth knowing some of the more common features and areas:
- Marketing & SEO
- Category management
- Scopes (Global, Website, Store, and Store View)
The questions are typically structured in two parts. They first gives a bit of background information, usually in the form of "you have been asked to do...", then ask you the question they want answering. Make sure to read the questions carefully as the background information often includes key words that might trip you up and trick you into answering the wrong question.
Quite a few answers are very similar, make sure you are confident in the exact file paths of files.
It may be beneficial to set up a throwaway Magento environment to test some of the things that you revise - such as managing the database using the Declarative Schema; something introduced within Magento 2.3. There were quite a few questions which involved knowledge regarding Data and Schema patches and being aware when to use them.
| Magento Version | 2.4.x |
| Magento Theme | Luma |
| Number of Questions | 60 |
| Time Limit | 90 Minutes |
| Passing Grade | 68% |
| Certification | Exam Content |
|---|---|
| Associate Developer | 33% |
| Professional Developer | 18% |
What are the significant steps to add a new module?
You need to create the following files:
registration.phpmodule.xml
This file is included by the Composer autoloader and is added to the static list of components in Magento\Framework\Component\ComponentRegistrar. Example:
<?php
use \Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
ComponentRegistrar::MODULE, // type
'YourCompany_YourModule', // componentName
__DIR__ // path
);Once Magento has found this file, it will then look to find etc/module.xml.
A component declares itself (that is, defines its name and existence) in the module.xml file located in the module's etc/ directory. This file specifies the loading sequence for the module and it's setup version (if not using Declarative Schema).
The sequence tells Magento which order to load modules in. This is done in Magento\Framework\Module\ModuleList\Loader.php and only occurs when the module is installed. This sequence is useful for events, plugins, preferences, and layouts.
- NB: If your module modifies the layout of another and your module is loaded first, the other module will overwrite your modifications.
Example:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="YourCompany_YourModule" setup_version="1.0.0">
<sequence>
<module name="TheirCompany_TheirModule" />
<module name="AnotherCompany_AnotherModule" />
</sequence>
</module>
</config>What are the different Composer package types?
| Name | Package Type | Description |
|---|---|---|
| Metapackage | metapackage | Technically, a Composer package type, not a Magento component type. A metapackage consists of only a composer.json file that specifies a list of components and their dependencies. For example, both Magento Open Source and Magento Commerce are metapackages. |
| Module | magento2-module | Code that modifies Magento application behavior. You can upload a single module to the Magento Marketplace or your module can be dependent on some parent package. |
| Theme | magento2-theme | Code that modifies the look and feel of the storefront or Magento Admin. |
| Language Package | magento2-language | Translations for the storefront or Admin. |
When would you place a module in the app/code folder versus another location?
Custom built modules and modules you build to extend other functionality are placed in the app/code/ directory.
Other modules, including extensions and the Magento 2 core modules, are placed in the vendor/ directory as they
are installed via Composer.
How do different modules interact with each other?
The way modules in Magento 2 interact with each other is by means of dependency injection, Service Contracts or Data Service Contracts. An important aspect of interaction is the scope in which the component is located. In other words, a Magento area. Some benefits of using service contracts is that these contracts ensure a well-defined, durable API that other modules and third-party extensions can implement. Also, these contracts make it easy to configure services as web APIs.
What side effects can come from this interaction?
If modules use Dependency injection, they can load in the wrong order or try to redefine the already redefined functionality of the module. To solve this problem, you should use sequence in module.xml.
If the modules use other modules’ logic and the module, whose logic is used, is disabled, dependencies will not be used and an error will occur when executing the code.
How do you locate different files in Magento?
All of the core Magento files are located in the vendor/magento/ directory with some supporting JavaScript and CSS files being stored in lib/.
Third-party files can be found in their respective vendor/vendor-name/module-name/ directories.
For your customisations:
- For modules, use
app/code. - For storefront themes, use
app/design/frontend. - For Admin themes, use
app/design/adminhtml. - For language packages,
use app/i18n.
The /Api directory stores the contracts or interfaces that are exposed to the API. An example of this would be Magento\Catalog\Api\CategoryListInterface.
This folder contains interfaces that represent data. Examples of this would be a product interface, a category interface, or a customer interface. The concrete implementations of these interfaces usually do little more than provide getters and setters for data.
See Magento\Catalog\Api\Data\ProductInterface for an example.
Blocks can be considered as template assistants. Very little functionality or business logic should be done in templates - that is the responsibility of the Block.
When running bin/magento on the command line, a list of available commands
to run is output. The code for commands should be placed inside the /Console directory.
This directory stores controller classes for web requests.
Definitions for cron jobs are stored here.
Any files directly within this directory are applied globally. You can restrict the area these files belong to by placing it in the relevant sub-directory - etc/frontend/, etc/adminhtml/ etc.
- NB: Some files MUST be placed within a particular area whilst others MUST be global.
Small, reusable snippets of code should be stored in a helper class.
This directory contains the translation CSV files for the module. These CSV files contain two columns, from and to.
A self-explanatory directory.
The classes stored in this directory dictate how data is stored and retrieved from the database. Any direct database interaction should be done within these files.
See vendor/magento/module-catalog/Model/ResourceModel/Product.php for an example.
When Magento fires an event, certain observers are called - decoupling the system. Magento Commerce integrates with RabbitMQ which allows even more control and reliability to this process. Event data should be able to be stored and then run in a queue at a later time.
Observers MUST implement the Magento\Framework\Event\ObserverInterface. The PHP class should follow the stand of using TitleCase while the event name should be snake_case.
Observers should not contain any business logic. This logic should instead be placed in another class and injected into your observer.
This directory stores your module's plugins. These are covered in more detail in a later section.
Stores the following files:
InstallSchema.php- Sets up table and column schema when the module is installed.
UpgradeSchema.php- Modifies table and column schema when the module version is upgraded.
Recurring.php- Runs after every install or upgrade.
InstallData.php- Sets up data when the module is installed. An example would be adding a custom CMS block.
UpgradeData.php- Modifies data after the module is installed and when the module version is upgraded.
RecurringData.php- Applies to data after every install or upgrade.
This directory stores your module's tests. Tests can be run via the command line using bin/magento dev:tests:run.
The counterpart to a Block is a template to render the HTML for the block. Whilst the block (in /Block) represents the business logic, the template represents how the results of the business logic are shown to the user.
Web assets such as images, CSS, JavaScript, LESS, and SCSS are stored in this directory.
HTML templates that can be requested asynchronously via JavaScript are stored in this directory. These files often contain KnockoutJS declarative bindings.
This directory contains the XML configuration for UI components. They are used to represent distinct UI elements, such as grids and forms, and are designed to provide flexible user interface rendering. Most Magento Admin grids (such as the Catalog Product grid and the Customer grid) are composed with UI components. The checkout on the frontend is also a UI component.
What are the naming conventions, and how are namespaces established?
The naming of classes and namespaces in Magento 2 conforms to the PSR-4 standard. Each class is located in a separate file and is declared in the namespace corresponding to a pattern of the type: {Vendor}\{Module}\{Path_1}\…\{Path_N}, where each {Path_N} corresponds to a specific folder containing the class file. The class names themselves correspond to the StudlyCaps notation.
How can you identify the files responsible for some functionality?
When searching for certain class files, remember that each class is in a separate file and the class namespace fully corresponds to the directory structure in which the file of this class is located. The configuration file of the di.xml module (etc/di.xml), which contains a list of the various module classes, can help you. To search for block files, you can use layout files from the module’s view/{area}/{layout} directory. You can also use the Template Path Hints tool to search for blocks and their associated template files.
Enable the Template Path Hints in the admin panel by navigating to Stores -> Configuration -> Advanced -> Developer -> Debug.
Controller files are located at the following folders of the module: Controllers/{Controller_Name}/{Action_name}.
Which configuration files are important in the development cycle?
Defines permissions for accessing protected resources.
Loads configuration values into Stores > Configuration in the Magento Admin. This file can also encrypt configuration entries.
Defines cron job scheduling.
This file configures dependency injection for your module. It defines plugins, preferences, concrete classes for interfaces, virtual types, and constructor argument modifications.
This file registers observers.
This file configures Magento indexers.
This file is required by Magento.
Triggers a type of event when data is modified in a database column - most often used for indexing.
This file is similar to config.xml but is used to specify the default values for design configuration.
Configures API access and routes.
Configures widgets to be used in products, CMS blocks, and CMS pages.
This file tells Magento that this area accepts web requests. The route node configures the first part of the layout handle (route ID) and the front name (first segment in the URL after the domain name).
Configuration for the menu in Magento Admin.
Configures tabs, sections, groups, and fields found in Store > Configuration in Magento Admin.
How do you identify the configuration scope for a given variable?
Scope values come from the store, store_group, and store_website tables.
- The
storetable specifies store view names and codes - The
store_websitetable specifies website names and codes - You can also find the code values using the Magento Admin.
How to read the table:
- Path in Magento Admin column
Values before the comma are paths in the Admin navigation. Values after the comma are options in the right pane.
- Variable name column is the name of the corresponding environment variable.
You have the option of specifying system values for these configuration parameters as environment variables if you wish.
- The entire variable name is always ALL CAPS
- Start a variable name with CONFIG__ (note two underscore characters)
- You can find the <STORE_VIEW_CODE> or <WEBSITE_CODE> portion of a variable name in either the Magento Admin or the Magento database, as indicated in the following sections.
Find a website or store view scope in the Magento Admin The following table summarizes how to find website or store view value in the Admin.
| Description | Path in Magento Admin | Variable name |
|---|---|---|
| Create, edit, delete store views | Stores > All Stores | CONFIG__STORES__<STORE_VIEW_CODE>__<SYSTEM__VARIABLE__NAME> |
| Create, edit, delete websites | Stores > All Stores | CONFIG__WEBSITES__<WEBSITE_CODE>__<SYSTEM__VARIABLE__NAME> |
How do native Magento scopes (for example, price or inventory) affect development and decision-making processes?
How can you fetch a system configuration value programmatically?
You can use the functions contained within the Magento\Framework\App\Config\ScopeConfigInterface class, passing the
configuration path as the minimum required parameter e.g. web/secure/base_url.
How can you override system configuration values for a given store using XML configuration?
Magento may load our custom system config and merge into the exist nodes. In our custom system config, we should try:
Vendor/ModuleName/etc/adminhtml/system.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="payment">
<group id="checkmo">
<field id="order_status" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1">
<label>Custom New Order Status</label> <!-- Custom label -->
</field>
</group>
</section>
</system>
</config>Remember to add overridden module - Magento_OfflinePayments
Vendor/ModuleName/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Vendor_YourModule" setup_version="1.0.0">
<sequence>
<module name="Magento_OfflinePayments"/>
</sequence>
</module>
</config>How are objects realized in code?
Since dependency injection happens automatically through the constructor, Magento must handle class creation - either at the time of injection or via a factory.
First the object manager locates the proper class type. If an interface is requested, hopefully an entry in di.xml will provide a concrete class for the interface (if not, an exception will be thrown).
Then the parameters for the constructor are loaded and recursively parsed meaning that the dependencies for the initially requested class are loaded as well as the dependencies of those dependencies as well.
The deploy mode (bin/magento deploy:mode:show) determines which class loader is used:
vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.phpvendor/magento/framework/ObjectManager/Factory/Dynamic/Production.php
Why is it important to have a centralized object creation process?
Having a centralised process to create objects makes testing much easier. It also provides a simple interface to substitute objects as well as modify existing ones.
How can you override a native class, inject your class into another object, and use other techniques available in
di.xml(for example,virtualTypes)?
preference nodes are used to substitute entire classes through di.xml. They can also be used to specify concrete classes for interfaces:
<preference for="Magento\GoogleTagManager\Block\ListJson"
type="YourCompany\YourModule\Path\To\Your\Class"
/>Specify a <type> entry with your class as an <argument> in di.xml:
<type name="Path\To\Your\Class\To\Inject\Into">
<arguments>
<argument xsi:type="object">
Path\To\Your\Injected\Class
</argument>
</arguments>
</type>A virtual type allows you to create an instance of an existing class that has custom constructor arguments. This is useful in cases where you need a “new” class only because the constructor arguments need to be changed. This is used frequently in Magento to reduce redundant PHP classes.
How would you obtain a class instance from different places in the code?
There are 2 ways to create new instance of objects in Magento 2. One is constructor injection. Second one is using a factory. Using Object manager directly in code should be avoided as much as possible.
How are plugins used in core code? How can they be used for customizations?
A plugin is a class that modifies the behavior of public class functions by intercepting a function call and running code before, after, or around that call. This allows you to customise or extend the behavior of original, public methods for any class or interface.
Before plugins are used when you want to modify the function input. To modify the input of a function:
public function beforeFunctionName(
Class\Containing\The\Function $subject,
$normalFunctionInput1,
$normalFunctionInput2,
) {
// ...
return [$normalFunctionInput1, $normalFunctionInput2];
}The return value determines the array of arguments being passed into the next plugin or targeted function.
After plugins are used when you want to modify the function output. To modify the output of a function:
public function afterFunctionName(
Class\Containing\The\Function $subject,
$result
) {
// ...
return $result;
}The return value determines the output of the function being passed into the next plugin or targeted function.
Around plugins give you full control over the function, it's inputs, and it's output. To use an around plugin to replace a function:
public function aroundFunctionName(
Class\Containing\The\Function $subject,
callable $proceed
) {
// ...
$result = $proceed();
// ...
return $result;
}To declare a plugin, add a <type/> to your module's di.xml:
<type name="Class\Containing\The\Function\To\Plug\Into">
<plugin name="PluginName"
type="Class\Containing\Your\Plugin"
disabled="false"
sortOrder="10"
/>
</type>Plugins have the following limitations:
- Only work with public functions
- Do not work with
finalclasses or functions - Do not work with
staticfunctions
How do multiple plugins interact?
The sortOrder from the plugins declared in di.xml determines the plugin’s prioritisation when more than one plugin is observing the same method.
The Magento\Framework\Interception\PluginListInterface which is implemented by Magento\Framework\Interception\PluginList\PluginList
is responsible to define when to call the before, around, or after methods respecting this prioritisation.
If two or more plugins have the same sortOrder value or do not specify it, the component load order declared in the <sequence> node from
module.xml and the area will define the merge sequence. The component load order can be checked in app/etc/config.php.
Magento executes plugins using these rules during each plugin execution in two main flows:
-
Before the execution of the observed method, starting from lowest to highest
sortOrder.- Magento executes the current plugin’s
beforemethod. - Then the current plugin’s
aroundmethod is called.- The first part of the plugin’s
aroundmethod is executed. - The
aroundmethod executes the callable.- If there is another plugin in the chain, all subsequent plugins are wrapped in an independent sequence loop and the execution starts another flow.
- If the current plugin is the last in the chain, the observed method is executed.
- The second part of the
aroundmethod is executed.
- The first part of the plugin’s
- Magento moves on to the next plugin.
- Magento executes the current plugin’s
-
Following the execution flow, starting from lowest to highest
sortOrderin the current sequence plugins loop.- The current plugin’s
aftermethod is executed. - Magento moves on to the next plugin.
- The current plugin’s
As a result of these rules, the execution flow of an observed method is affected not only by the prioritisation of the plugins, but also by their implemented methods.
Examples of how this prioritisation is realised can be found in the [Magento 2 dev docs regarding plugins and interceptors])https://devdocs.magento.com/guides/v2.4/extension-dev-guide/plugins.html#examples.
How can the plugin execution order be controlled?
The sortOrder attribute defines the order in which to execute plugins, starting from the lowest and working through to the highest.
What are the limitations of using plugins for customization?
Plugins can not be used on the following:
- Final methods
- Final classes
- Non-public methods
- Class methods (such as static methods)
__construct- Virtual types
- Objects that are instantiated before
Magento\Framework\Interception is bootstrapped
In which cases should plugins be avoided?
Plugins are useful to modify the input, output, or execution of an existing method. Plugins are also best to be avoided in situations where an event observer will work. Events work well when the flow of data does not have to be modified.
- Interception
4.1. Around-plugins SHOULD only be used when behavior of an original method is supposed to be substituted in certain scenarios.
4.2. Plugins SHOULD NOT be used within own module .
4.3. Plugins SHOULD NOT be added to data objects.
4.4. Plugins MUST be stateless.
...
- Events
14.1. All values (including objects) passed to an event MUST NOT be modified in the event observer. Instead, plugins SHOULD BE used for modifying the input or output of a function.
Avoid using around method plugins when they are not required because they increase stack traces and affect performance. The only use case for around method plugins is when the execution of all further plugins and original methods need termination. Use after method plugins if you require arguments for replacing or altering function results.
Observers listen for events that are triggered in Magento. Scheduled jobs perform an action at a specified interval.
Observers MUST implement the Magento\Framework\Event\ObserverInterface.
How are observers registered?
Create an <event/> node in your etc/[area]/events.xml file:
<event name="event_for_your_observer_to_listen_for">
<observer name="observerName"
instance="Your\Observer\Class"
/>
</event>How are they scoped for frontend or backend?
Place the events.xml file in the etc/frontend/ and etc/adminhtml/ directories respectively.
How are automatic events created, and how should they be used?
Events should be used when you do not want to change the data. They can be triggered by injecting an instance of Magento\Framework\Event\ManagerInterface into the constructor and calling: $this->eventManager->dispatch('event_name', [params]);.
How are scheduled jobs configured?
To configure a scheduled job you need to assign it a name, specify the function it should execute, the class that function belongs to, and set the schedule using the regular cron schedule notatation. Scheduled jobs are specified in the etc/crontab.xml file:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
<group id="default">
<job name="cron_job_name"
instance="Path\To\Your\Class"
method="execute">
<schedule>*/5 * * * *</schedule>
</job>
</group>
</config>Which commands are available?
A full list of commands can be found by running bin/magento. All of the commands listed below can be run from within the magento/ directory via the command line, prefixed with bin/magento.
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
help Displays help for a command
list Lists commands
admin
admin:user:create Creates an administrator
admin:user:unlock Unlock Admin Account
app
app:config:dump Create dump of application
app:config:import Import data from shared configuration files to appropriate data storage
app:config:status Checks if config propagation requires update
cache
cache:clean Cleans cache type(s)
cache:disable Disables cache type(s)
cache:enable Enables cache type(s)
cache:flush Flushes cache storage used by cache type(s)
cache:status Checks cache status
catalog
catalog:images:resize Creates resized product images
catalog:product:attributes:cleanup Removes unused product attributes.
config
config:sensitive:set Set sensitive configuration values
config:set Change system configuration
config:show Shows configuration value for given path. If path is not specified, all saved values will be shown
cron
cron:install Generates and installs crontab for current user
cron:remove Removes tasks from crontab
cron:run Runs jobs by schedule
customer
customer:hash:upgrade Upgrade customer's hash according to the latest algorithm
deploy
deploy:mode:set Set application mode.
deploy:mode:show Displays current application mode.
dev
dev:di:info Provides information on Dependency Injection configuration for the Command.
dev:profiler:disable Disable the profiler.
dev:profiler:enable Enable the profiler.
dev:query-log:disable Disable DB query logging
dev:query-log:enable Enable DB query logging
dev:source-theme:deploy Collects and publishes source files for theme.
dev:template-hints:disable Disable frontend template hints. A cache flush might be required.
dev:template-hints:enable Enable frontend template hints. A cache flush might be required.
dev:tests:run Runs tests
dev:urn-catalog:generate Generates the catalog of URNs to *.xsd mappings for the IDE to highlight xml.
dev:xml:convert Converts XML file using XSL style sheets
encryption
encryption:payment-data:update Re-encrypts encrypted credit card data with latest encryption cipher.
i18n
i18n:collect-phrases Discovers phrases in the codebase
i18n:pack Saves language package
i18n:uninstall Uninstalls language packages
indexer
indexer:info Shows allowed Indexers
indexer:reindex Reindexes Data
indexer:reset Resets indexer status to invalid
indexer:set-dimensions-mode Set Indexer Dimensions Mode
indexer:set-mode Sets index mode type
indexer:show-dimensions-mode Shows Indexer Dimension Mode
indexer:show-mode Shows Index Mode
indexer:status Shows status of Indexer
info
info:adminuri Displays the Magento Admin URI
info:backups:list Prints list of available backup files
info:currency:list Displays the list of available currencies
info:dependencies:show-framework Shows number of dependencies on Magento framework
info:dependencies:show-modules Shows number of dependencies between modules
info:dependencies:show-modules-circular Shows number of circular dependencies between modules
info:language:list Displays the list of available language locales
info:timezone:list Displays the list of available timezones
maintenance
maintenance:allow-ips Sets maintenance mode exempt IPs
maintenance:disable Disables maintenance mode
maintenance:enable Enables maintenance mode
maintenance:status Displays maintenance mode status
module
module:disable Disables specified modules
module:enable Enables specified modules
module:status Displays status of modules
module:uninstall Uninstalls modules installed by composer
queue
queue:consumers:list List of MessageQueue consumers
queue:consumers:start Start MessageQueue consumer
sampledata
sampledata:deploy Deploy sample data modules for composer-based Magento installations
sampledata:remove Remove all sample data packages from composer.json
sampledata:reset Reset all sample data modules for re-installation
setup
setup:backup Takes backup of Magento Application code base, media and database
setup:config:set Creates or modifies the deployment configuration
setup:cron:run Runs cron job scheduled for setup application
setup:db-data:upgrade Installs and upgrades data in the DB
setup:db-declaration:generate-patch Generate patch and put it in specific folder.
setup:db-declaration:generate-whitelist Generate whitelist of tables and columns that are allowed to be edited by declaration installer
setup:db-schema:upgrade Installs and upgrades the DB schema
setup:db:status Checks if DB schema or data requires upgrade
setup:di:compile Generates DI configuration and all missing classes that can be auto-generated
setup:install Installs the Magento application
setup:performance:generate-fixtures Generates fixtures
setup:rollback Rolls back Magento Application codebase, media and database
setup:static-content:deploy Deploys static view files
setup:store-config:set Installs the store configuration. Deprecated since 2.2.0. Use config:set instead
setup:uninstall Uninstalls the Magento application
setup:upgrade Upgrades the Magento application, DB data, and schema
store
store:list Displays the list of stores
store:website:list Displays the list of websites
theme
theme:uninstall Uninstalls theme
How are commands used in the development cycle?
Commands provide a secure method of perfoming tasks that may otherwise be insecure or more time consuming to perform through the Magento Admin. Some of the more commonly used commands during development are listd below:
Disables specific caches. You might use this to disable the layout, block_html, and full_page caches during the development of some frontend templates so Magento always generates the pages you are working on rather than older versions that it has cached. Example:
bin/magento cache:disable layout block_html full_page
Destroys the Magento caches, deleting the cache keys. This can be used to destroy any of the Magento caches in combination. Example:
# destroy all caches
bin/magento cache:flush
# destroy configuration cache
bin/magento cache:flush config
Lists the caches and whether they are enabled or disabled. You might use this prior to using the cache:disable or cache:enable commands.
Sets your deploy mode. During development you will likely want to set this to developer whilst on your live server you will want to set this to production. Example:
# developer mode
bin/magento deploy:mode:set developer
# production mode
bin/magento deploy:mode:set production
# default mode
bin/magento deploy:mode:set default
Enables database query logging.
Runs the Magento indexers.
Disables a specified module. Example:
bin/magento module:disable Module_Name
Enables a specified module. Example:
bin/magento module:enable Module_Name
List all modules and whether they are enabled or disabled.
Checks whether the Magento database needs to be upgraded.
Synchronises module versions in the database with those defined in the codebase.
How would you install and verify an extension by a customer’s request?
We recommend working in a development branch when adding an extension to your implementation. If you do not have a branch, see the Get started creating branches topic. When installing an extension, the extension name (_) is automatically inserted in the app/etc/config.php file. There is no need to edit the file directly.
To install an extension:
-
On your local workstation, change to the Cloud project root directory.
-
Create or checkout a development branch. See branching.
-
Using the Composer name and version, add the extension to the require section of the composer.json file.
composer require <extension-name>:<version> --no-update
For example:
composer require pixlee/magento2:1.0.1 --no-update
- Update the project dependencies.
composer update
- Add, commit, and push code changes.
git add -A
git commit -m "Install <extension-name>"
git push origin <branch-name>
When installing an extension, you must include the composer.lock file when you push code changes to the remote environment. The composer install command reads the composer.lock file to enable the defined dependencies in the remote environment.
After the build and deploy finishes, use a SSH to log in to the remote environment and verify the extension installed.
bin/magento module:status <extension-name>
An extension name uses the format: _.
Sample response:
Module is enabled
| Certification | Exam Content |
|---|---|
| Associate Developer | 7% |
| Professional Developer | 12% |
Understand the pros and cons of using developer mode or production mode.
This mode should be used on your live production server. Production mode leads to an increase in performance by providing all necessary static files at the time of deployment rather than requiring Magento to dynamically locate and create static files during run time.
In this mode Magento:
- Logs exceptions and does not show exceptions on the frontend
- Serves static view files from the cache only
- Prevents automatic code compilation meaning that new or updated files are not written to the file system
- Prevents you from enabling or disabled cache types via Magento Admin
As it's name suggests, this mode is intended to be used during development only. When in this mode, Magento:
- Disables static view file caching instead writing them to
pub/staticevery time they are called - Provides verbose logging in
var/report - Enables automatic code compilation
- Displays uncaught exceptions to the frontend
- Enables enhanced debugging
- Shows custom
x-magento-*HTTP request and response headers - Performs slower
When do you use default mode?
As its name implies, default mode is how Magento operates if no other mode is specified.
It enables you to deploy the Magento application on a single server without changing any settings.
However, default mode is not as optimized for production.
To deploy the Magento application on more than one server or to optimize it for production, change to one of the other modes.
In default mode:
- Errors are logged to the file reports at server, and never shown to a user
- Static view files are cached
- Not optimized for a production environment, primarily because of the adverse performance impact of static files being dynamically generated rather than materialized. In other words, creating static files and caching them has a greater performance impact than generating them using the static files creation tool.
How do you enable/disable maintenance mode?
Maintenance mode can be enabled and disabled via the command line:
# enable maintenance mode
bin/magento maintenance:enable
# disable maintenance mode
bin/magento maintenance:disable
Identify the steps for application initialisation.
How would you design a customization that should act on every request and capture output data regardless of the controller?
Describe front controller responsibilities.
In which situations will the front controller be involved in execution, and how can it be used in the scope of customizations?
URL rewrites provide a user-friendly URL to the customer in place of a cumbersome Magento URL. These values are stored in the url_rewrite table.
How is the user-friendly URL of a product or category defined?
The product/category url_key attribute defines their URL. For each category a product belongs to, Magento will generate a URL based on the category tree before appending the product's url_key.
How can you change a URL?
You can change a URL by creating a URL rewrite. The following actions also cause a URL to change:
- Updating a category's
url_keyattribute - Updating a product's
url_keyattribute - Modifying the categories a product belongs to
How do you determine which page corresponds to a given user-friendly URL?
In the url_rewrite table you will find a row where the request_path value is the user-friendly URL. The corresponding target_path value is the internal Magento page. The Magento_UrlRewrite module contains a router that checks to see whether the given URL can be matched to a request_path in the url_rewrite table, redirecting to the target_path if a match is found.
How do you identify which module/controller corresponds to a given URL?
https://your-store.com/catalog/product/view/id/42
What would you do to create a given URL?
Set the Category and Product url_key attributes. You can also create URL rewrites through the Magento Admin path Marketing > SEO & Search > URL Rewrites
Describe how action controllers and results function.
How do controllers interact with each other?
How are different response types generated?
| Certification | Exam Content |
|---|---|
| Associate Developer | 15% |
| Professional Developer | 10% |
When would you create a new theme?
You would create a new theme when making design changes to the Magento frontend or admin. This typically involves copying and modifying layout files, templates, and styles to achieve your desired design.
How do you define theme hierarchy for a project?
The theme.xml file can be used to specify the theme's parent using the <parent /> node:
<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
<title>Your Theme Name</title>
<parent>Vendor/Theme</parent>
</theme>Omitting the <parent /> node dictates that the theme is the base, or default, theme.
How do you assign a template to a block?
To assign a template to a block:
<block class="Namespace\Of\Your\Class"
name="blockName"
template="Module_Name::path/to/your/template.phtml"
/>NB: The path/to/your/template.phtml starts from the templates/ directory.
How do you assign a different template to a native block?
To assign a template to an existing block, pass an argument to the block:
<referenceBlock name="blockName">
<action method="setTemplate">
<argument name="template" xsi:type="string">
Module_Name::path/to/your/template.phtml
<argument>
</action>
</referenceBlock>When would you use non-template block types?
| Block Type | Path | Use |
|---|---|---|
| Text | vendor/magento/framework/View/Element/Text.php |
Printing a string |
| ListText | vendor/magento/framework/View/Element/Text/ListTest.php |
Output each of the child blocks |
How do you use layout XML directives in your customizations?
Layout XML is what links templates to blocks and there are a number of directives available for use.
Defines a block. A block is a unit of page output that renders some distinctive content (anything visually tangible for the end-user), such as a piece of information or a user interface element. Blocks are a foundational building unit for layouts in Magento. They are the link between a PHP block class (which contains logic) and a template (which renders content). Blocks can have children and grandchildren (and so on).
| Attribute | Description | Values | Required |
|---|---|---|---|
class |
Name of a class that implements rendering of a particular block. An object of this class is responsible for actual rendering of block output. | Class name | No |
name |
Name that can be used to address the block to which this attribute is assigned. The name must be unique per generated page. If not specified, an automatic name will be assigned in the format ANONYMOUS_n. |
0-9, A-Z, a-z, underscore (_), period (.), dash (-). Should start with a letter. Case-sensitive. |
No |
before |
Used to position the block before an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block before all other elements of its level of nesting. |
Element name or dash (-). |
No |
after |
Used to position the block after an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block after all other elements of its level of nesting. |
Element name or dash (-). |
No |
template |
A template that represents the functionality of the block to which this attribute is assigned. | Template file name | No |
as |
An alias name that serves as identifier in the scope of the parent element. | Same as name |
No |
cachable |
Defines whether a block element is cacheable. This can be used for development purposes and to make needed elements of the page dynamic. | true or false |
No |
@TODO: <block /> exampleA structure without content that holds other layout elements such as blocks and containers. A container renders child elements during view output generation. It can be empty or it can contain an arbitrary set of <container> and <block> elements. If the <container> is empty, and there is no child <block> available, it will not be displayed in the frontend source code.
| Attribute | Description | Values | Required |
|---|---|---|---|
name |
Name that can be used to address the block to which this attribute is assigned. The name must be unique per generated page. If not specified, an automatic name will be assigned in the format ANONYMOUS_n. |
0-9, A-Z, a-z, underscore (_), period (.), dash (-). Should start with a letter. Case-sensitive. |
No |
label |
An arbitrary name to display in the web browser. | Any | No |
before |
Used to position the block before an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block before all other elements of its level of nesting. |
Element name or dash (-). |
No |
after |
Used to position the block after an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block after all other elements of its level of nesting. |
Element name or dash (-). |
No |
as |
An alias name that serves as identifier in the scope of the parent element. | Same as name |
No |
output |
Defines whether to output the root element. If specified, the element will be added to output list. If not specified, the parent element is responsible for rendering its children. | Any value except the obsolete toHtml. Recommended value is 1. |
No |
htmlTag |
Output parameter. If specified, the output is wrapped into specified HTML tag. | Any valid HTML5 tag | No |
htmlID |
Output parameter. If specified, the value is added to the wrapper element. If there is no wrapper element, this attribute has no effect. | Any valid HTML5 id value |
No |
htmlClass |
Output parameter. If specified, the value is added to the wrapper element. If there is no wrapper element, this attribute has no effect. | Any valid HTML5 class value |
No |
@TODO: <container /> exampleUpdates in <referenceBlock> and <referenceContainer> are applied to the corresponding <block> or <container>. For example, if you make a reference by <referenceBlock name="right">, you are targeting the block <block name="right">.
| Attribute | Description | Values | Required |
|---|---|---|---|
remove |
Allows you to remove or cancel the removal of the element. When a container is removed, its child elements are removed as well. | true or false |
No |
display |
Allows you to disable rendering of specific block or container with all its children (both set directly and by reference). The block’s/container’s and its children’ respective PHP objects are still generated and available for manipulation. | true or false |
No |
The remove attribute is optional and its default value is false This implementation allows you to remove a block or container in your layout by setting the remove attribute value to true, or to cancel the removal of a block or container by setting the value to false.
<referenceBlock name="blockName" remove="true" />The display attribute is optional and its default value is true. You are always able to overwrite this value in your layout. In situation when the remove value is true, the display attribute is ignored.
<referenceContainer name="containerName" display="false" /><arguments> is a required container for <argument>. It does not have its own attributes.
<arguments>
...
</arguments>Information can be passed from layout XML files to blocks using the <argument /> node. These directives must always be enclosed within <arguments /> directives. Argument values set in a layout file are added to the block's data array and can be accessed in templates using the getData('argumentName') and hasData('argumentName') functions. The latter returns a boolean defining whether there’s any value set.
| Attribute | Description | Values | Required |
|---|---|---|---|
name |
Argument name. | Must be unique. | Yes |
xsi:type |
Argument type. | string / boolean / object / number / null / array / options / url / helper |
Yes |
translate |
true or false |
No |
<arguments>
<!-- String -->
<argument name="stringArgName" xsi:type="string">
Some String
</argument>
<!-- Boolean -->
<argument name="booleanArgName" xsi:type="boolean">
true
</argument>
<!-- Object -->
<argument name="objectArgName" xsi:type="object">
<!-- Must implement `Magento\Framework\View\Element\Block\ArgumentInterface` -->
Namespace\To\Your\Class
</argument>
<!-- Number -->
<argument name="numberArgName" xsi:type="number">
42
</argument>
<!-- Null -->
<argument name="nullArgName" xsi:type="null" />
<!-- Array -->
<argument name="arrayArgName" xsi:type="array">
<item name="arrayKeyOne" xsi:type="string">First Item</item>
<item name="arrayKeyTwo" xsi:type="object">Namespace\Of\Your\Class</item>
...
</argument>
<!-- Options -->
<argument name="optionsArgName" xsi:type="options">
<!-- Must implement `Magento\Framework\Data\OptionSourceInterface` -->
Namespace\Of\Your\Class
</argument>
<!-- URL -->
<argument name="urlArgName"
xsi:type="url"
path="your/url/path"
/>
<!-- Helper -->
<argument name="helperArgName"
xsi:type="string"
helper="Namespace\To\Your\Helper\Class::helperFunction">
<param name="paramName">paramValue</param>
</argument>
<arguments>NB: The helper can only use public functions.
Sets the declared block or container element as a child of another element in the specified order.
| Attribute | Description | Values | Required |
|---|---|---|---|
element |
Name of the element to move. | Element name | Yes |
destination |
Name of the target parent element. | Element name | Yes |
as |
Alias name for the element in the new location. | 0-9, A-Z, a-z, underscore (_), period (.), dash (-). Case-sensitive. |
No |
after or before |
Specifies the element’s position relative to siblings. Use dash (-) to position the block before or after all other siblings of its level of nesting. If the attribute is omitted, the element is placed after all siblings. |
Element name | No |
<move element="elementName"
destination="parentElementName"
as="newAlias"
after="siblingElementName"
before="anotherSiblingElementName"
/>NB:
<move>is skipped if the element to be moved is not defined.- If the
asattribute is not defined, the current value of the element alias is used. If that is not possible, the value of thenameattribute is used instead. - During layout generation, the
<move>instruction is processed before the removal (set using theremoveattribute). This means if any elements are moved to the element scheduled for removal, they will be removed as well.
<remove> is used only to remove the static resources linked in a page <head> section. For removing blocks or containers, use the remove attribute for <referenceBlock> and <referenceContainer>.
<!-- Remove local resources -->
<remove src="css/styles-m.css" />
<remove src="my-js.js"/>
<remove src="Magento_Catalog::js/compare.js" />
<!-- Remove external resources -->
<remove src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css"/>
<remove src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"/>
<remove src="http://fonts.googleapis.com/css?family=Montserrat" />Includes a certain layout file.
<update handle="{handleNameToInclude}" />How do you register a new layout file?
If the new page has a 3-columns-double-footer layout, create a custom page-layout XML file: app/design/frontend/<VendorName>/<ThemeName>/Magento_Theme/page_layout/3-columns-double-footer.xml.
<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
<update handle="3columns"/>
<referenceContainer name="page.wrapper">
<container name="footer-bottom" as="footer-bottom" after="footer" label="Footer Bottom" htmlTag="footer" htmlClass="page-footer-bottom">
<container name="footer-bottom-content" as="footer-bottom-content" htmlTag="div" htmlClass="footer content">
<block class="Magento\Framework\View\Element\Template" name="report.bugs.bottom" template="Magento_Theme::html/bugreport.phtml"/>
</container>
</container>
</referenceContainer>
</layout>Add the newly created page layout to the layouts.xml file of the theme directory: app/design/frontend/<VendorName>/<ThemeName>/Magento_Theme/layouts.xml.
<?xml version="1.0" encoding="UTF-8"?>
<page_layouts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/PageLayout/etc/layouts.xsd">
<layout id="3-columns-double-footer">
<label translate="true">3 Columns Double Footer</label>
</layout>
</page_layouts>Clean the cache by going to System > Cache Management > Flush Magento Cache or bin/magento cache:clean
How do you pass variables from layout to block?
Information can be passed from layout XML files to blocks using the <argument /> node.
These directives must always be enclosed within <arguments /> directives. Argument values set in a layout file
are added to the block's data array and can be accessed in templates using the getData('argumentName') and
hasData('argumentName') functions. The latter returns a boolean defining whether there’s any value set.
| Attribute | Description | Values | Required |
|---|---|---|---|
name |
Argument name. | Must be unique. | Yes |
xsi:type |
Argument type. | string / boolean / object / number / null / array / options / url / helper |
Yes |
translate |
true or false |
No |
<arguments>
<!-- String -->
<argument name="stringArgName" xsi:type="string">
Some String
</argument>
<!-- Boolean -->
<argument name="booleanArgName" xsi:type="boolean">
true
</argument>
<!-- Object -->
<argument name="objectArgName" xsi:type="object">
<!-- Must implement `Magento\Framework\View\Element\Block\ArgumentInterface` -->
Namespace\To\Your\Class
</argument>
<!-- Number -->
<argument name="numberArgName" xsi:type="number">
42
</argument>
<!-- Null -->
<argument name="nullArgName" xsi:type="null" />
<!-- Array -->
<argument name="arrayArgName" xsi:type="array">
<item name="arrayKeyOne" xsi:type="string">First Item</item>
<item name="arrayKeyTwo" xsi:type="object">Namespace\Of\Your\Class</item>
...
</argument>
<!-- Options -->
<argument name="optionsArgName" xsi:type="options">
<!-- Must implement `Magento\Framework\Data\OptionSourceInterface` -->
Namespace\Of\Your\Class
</argument>
<!-- URL -->
<argument name="urlArgName"
xsi:type="url"
path="your/url/path"
/>
<!-- Helper -->
<argument name="helperArgName"
xsi:type="string"
helper="Namespace\To\Your\Helper\Class::helperFunction">
<param name="paramName">paramValue</param>
</argument>
<arguments>NB: The helper can only use public functions.
How do you add new content to existing pages using layout XML?
| Certification | Exam Content |
|---|---|
| Associate Developer | 18% |
| Professional Developer | 7% |
What are the responsibilities of each of the ORM object types?
The Magento ORM elements are:
- Models: Define entities, their data, and their behaviour.
- Resource Models: Data mappers for storage structures.
- Collections: Stores sets of Models and related functionality including filtering, sorting, and pagination.
- Resources: Maintain database connections through adapters.
How do they relate to one another?
- Models are like a black box which provides a layer of abstraction on top of the resource models. The fetching, extraction, and manipulation of data occur through models. As a rule of thumb, every entity we create (i.e. every table we create in our database) should have its own model class. Every model extends the
Magento\Framework\Model\AbstractModelclass, which inherits the\Magento\Framework\DataObjectclass, hence, we can call thesetData()andgetData()functions on our model, to get or set the data of a model respectively. - All of the actual database operations are executed by the resource model. Every model must have a resource model, since all of the methods of a resource model expects a model as its first parameter. All resource models must extend the
Magento\Framework\Model\ResourceModel\Db\AbstractDbclass. - Collections are used when we want to fetch multiple rows from our table. Meaning collections are a group of models.
How do you use the native Magento save/load process in the development process?
-
Load: First calls
beforeLoad()which can be used for plugin. Creates connection to database and loads a select query using parameters to fetch the row and set the data. Then callsafterLoad()method for plugins and object is returned. -
Save: If object is deleted then it deletes it. If object is not modified then it is committed and method is returned. Checks for validation before save then
beforeSave()is called. If object can be saved then it is saved and afterSave is called and event is dispatched.
You can use native Magento load/save to do basic get/set and customize it with plugins.
- Filter:
$collection->addFieldToFilter() - Sort:
$collection->addOrder() - Select Column:
$collection->addFieldToSelect() - Pagination:
$collection->setPageSize()and$collection->setCurPage()
Repositories give service requestors the ability to perform create, read, update, and delete (CRUD) operations on entities or a list of entities. A repository is an example of a service contract, and its implementation is part of the domain layer.
A repository should be stateless after instantiation. This means that every method call should not rely on previous calls nor should it affect later method calls. Any field contained in the repository class must also be stateless.
If your repository needs to provide functionality that requires state, such as for caching, use the registry pattern. A good example that uses this pattern is the CustomerRepository class.
- Search Criteria
A Search Criteria is an implementation of the
SearchCriteriaInterfaceclass that allows you to build custom requests with different conditions.
Repositories use this class to retrieve entities based on a matching criteria.
- Filter The Filter class is the smallest part of a Search Criteria. It allows you to add a custom field, value, and condition type to the criteria.
Example of how to define a Filter:
$filter
->setField("url")
->setValue("%magento.com")
->setConditionType("like");This filter will find all urls with the suffix of “magento.com”.
- Filter Group
The FilterGroup class acts like a collection of Filters that apply one or more criteria to a search.
The boolean OR statement joins Filters inside a single Filter Group. The boolean AND statement joins Filter Groups inside a Search Criteria.
For example:
$filter1
->setField("url")
->setValue("%magento.com")
->setConditionType("like");
$filter2
->setField("store_id")
->setValue("1")
->setConditionType("eq");
$filterGroup1->setFilters([$filter1, $filter2]);
$filter3
->setField("url_type")
->setValue(1)
->setConditionType("eq");
$filterGroup2->setFilters([$filter3]);
$searchCriteria->setFilterGroups([$filterGroup1, $filterGroup2]);The code above creates a Search Criteria with the Filters put together in the following way: (url like %magento.com OR store_id eq 1) AND (url_type eq 1)
- Sorting
To apply sorting to the Search Criteria, use the SortOrder class.
Field and direction make up the two parameters that define a Sort Order object. The field is the name of the field to sort. The direction is the method of sorting whose value can be ASC or DESC.
The example below defines a Sort Order object that will sort the customer email in ascending order:
$sortOrder
->setField("email")
->setDirection("ASC");
$searchCriteria->setSortOrders([$sortOrder]);- Pagination
The
setPageSizefunction paginates the Search Criteria by limiting the amount of entities it retrieves:
$searchCriteria->setPageSize(20); //retrieve 20 or less entitiesThe setCurrentPage function sets the current page:
$searchCriteria
->setPageSize(20)
->setCurrentPage(2); //show the 21st to 40th entityhttps://devdocs.magento.com/guides/v2.2/extension-dev-guide/searching-with-repositories.html
How do you select a subset of records from the database?
For getList method, a SearchCriteria object with set parameters has to be passed in the method.
- Search Criteria: A
SearchCriteriaobject contains smaller objects such as filters and filter groups.- Filter:
Filterclass is the smallest object ofSearchCriteriaobject and allows you to filter searches with set fields, values and conditions. - Filter Group: Like a filter but allows you to apply multiple filters to a search.
ORstatements join filters in a single filter group.ANDstatements join filter groups inside the search criteria object. - Sort Order: Sorts the results returned from search criteria and takes in field parameter (e.g. email) and direction parameter (e.g. ASC).
- Filter:
Declarative schema in Magento 2.3 allows developers to declare the final desired state of the database and has the system adjust to it automatically, without performing redundant operations. Developers are no longer forced to write scripts for each new version. Additionally, this approach allows data be deleted when a module is uninstalled - something that previously had to be done separately.
Data Patch
- A class that contains data modification instructions. It can have dependencies on other data or schema patches.
- Some data patches can be reverted as a module or patch is uninstalled or deleted. Revertable operations are Data Query Language (DQL) and Data Manipulation Language (DML) operations:
INSERT,UPDATE.
Schema Patch
- A class that contains custom schema modification instructions. Schema patches are used along with declarative schema, but these patches allow complex operations such as:
- Adding triggers, stored procedures, or functions
- Performing data migration with inside DDL operations
- Renaming tables, columns, and other entities
- Adding partitions and options to a table
How do you add a column using declarative schema?
You can create/modify the etc/db_schema.xml file, specifying a <table /> node for the table you are editing and adding a <column /> node inside to create the new column.
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="table_name">
<column xsi:type="varchar"
name="title"
padding="10"
comment="Page Title"
/>
</table>
</schema>You can also create a schema patch file in the YourCompany\YourModule\Setup\Patch\Schema namespace:
<?php
namespace YourCompany\YourModule\Setup\Patch\Schema;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\Patch\SchemaPatchInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
class YourSchemaPatch implements SchemaPatchInterface
{
/** @var SchemaSetupInterface */
private $moduleSchemaSetup;
/**
* YourSchemaPatch Constructor.
*
* @param SchemaSetupInterface $moduleSchemaSetup
*/
public function __construct(SchemaSetupInterface $moduleSchemaSetup)
{
$this->moduleSchemaSetup = $moduleSchemaSetup;
}
/**
* {@inheritdoc}
*/
public function apply()
{
$this->schemaSetup->startSetup();
$table = $this->schemaSetup->getTable('your_table_name');
$connection = $this->schemaSetup->getConnection();
if ($connection->isTableExists($table)) {
// declare new columns to add
$newColumns = [
'shiny_new_column' => [
'type' => Table::TYPE_TEXT,
'nullable' => true,
'comment' => 'Shiny New Column',
],
'another_shiny_column' => [
'type' => Table::TYPE_TEXT,
'nullable' => true,
'comment' => 'OMG More Shinies! :O',
],
];
foreach ($newColumns as $newColumn => $columnDescription) {
$connection->addColumn($table, $newColumn, $columnDescription);
}
}
$this->schemaSetup->endSetup();
}
/**
* {@inheritDoc}
*/
public static function getDependencies()
{
// return [dependencies]
}
/**
* {@inheritDoc}
*/
public function getAliases()
{
// return [aliases]
}
}NB: When adding new columns to a table, you also need to generate the db_schema_whitelist.json file.
How do you modify a table added by another module?
To modify a table added by another module, create Your_Company/Your_Module/etc/db_schema.xml and specify the table name in the <table /> node:
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="table_create_by_other_module">
...
</table>
</schema>How do you delete a column?
To remove a column from a table created by your module you can simply remove the corresponding <column /> node in Your_Company/Your_Module/etc/db_schema.xml. To drop a column declared in another module, you must redeclare it and set the disabled attribute to true:
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="table_create_by_other_module">
...
<column xsi:type="int"
name="new_id"
padding="10"
unsigned="true"
nullable="false"
comment="New ID"
disabled="true"
/>
...
</table>
</schema>How do you add an index or foreign key using declarative schema?
To add an index, declare an <index /> node in Your_Company/Your_Module/etc/db_schema.xml:
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="table_create_by_other_module">
...
<index referenceId="INDEX_NAME" indexType="btree">
<column name="column_name" />
</index>
...
</table>
</schema>To add a foreign key, declare a <constraint /> node with an xsi:type of foreign in Your_Company/Your_Module/etc/db_schema.xml:
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="table_create_by_other_module">
...
<constraint xsi:type="foreign"
referenceId="YOUR_REFERENCE_ID"
<!-- The current table -->
table="table_name"
<!-- The column in the current table that refers to a column in another table -->
column="column_name"
<!-- The table being referenced -->
referenceTable=""
<!-- The column being referenced -->
referenceColumn=""
<!-- Foreign key trigger (CASCADE/SET/NULL/NO ACTION) -->
onDelete="CASCADE"
/>
...
</table>
</schema>How do you manipulate data using data patches?
What is the purpose of schema patches?
Schema patches are used to make custom database schema modifications:
- Renaming tables
- Adding/removing columns
- Setting primary & foreign keys
| Certification | Exam Content |
|---|---|
| Associate Developer | 11% |
| Professional Developer | 10% |
How would you create an admin controller?
Admin routes go in /etc/adminhtml/routes.xml and admin router node uses id=”admin” instead of id=”standard”. All admin routes have /admin/ as the first segment of the URL.
The controller folder directory is [Package]\[Module]\Controller\Adminhtml\[Controller Segment]\[Action Segment] which is similar to its front end counterpart but with no /Adminhtml/ segment. The controller also must inherit from Magento\Backend\App\Action along with a $context variable if using __contruct() method.
How do you ensure the right level of security for a new controller?
_isAllowed() is a required method for admin controllers and typically uses ACL rules to return true for access.
The view/adminhtml/layout directory uses routeId_controller_action.xml to connect layout to route.
5.2 Define basic terms and elements of system configuration, including scopes, website, store, store view
How would you add a new system configuration option?
The system configuration goes in etc/adminhtml/system.xml and has element nodes like group, tab, section, and fields.
To set default values of system.xml, use the etc/config.xml file.
List of scopes ranges:
- Global scope: System-wide settings and resources
- Website scope: Settings and resources that are limited to the current website. Each website has a default store.
- Store scope: Settings and resources that are limited to the current store. Each store has a default root category (main menu) and default store view.
- Store view scope: Settings and resources that are limited to the current store view.
The parameters
showInDefault = “1”,showInWebsite = “1”andshowInStore = “1”indicate which scope it is available.
What is the difference in this process for different option types (secret, file)?
How would you add a new ACL resource to a new entity?
Your controller in the admin application must implement an _isAllowed() method or const ADMIN_RESOURCE which determines if a user can access the URL endpoint.
How do you manage the existing ACL hierarchy?
Editing etc/acl.xml. sorOrder define the position where the option is displayed in the menu.
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magenest_HelloWorld::helloworld" title="Hello World" sortOrder="51">
<resource id="Magenest_HelloWorld::post" title="Manage Post" sortOrder="10"/>
<resource id="Magenest_HelloWorld::helloworld_configuration" title="Configuration" sortOrder="99" />
</resource>
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Magenest_HelloWorld::helloworld_config" title="Hello World"/>
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>How do you add a new menu item to a given tab?
Adminhtml menu items are configured in etc/adminhtml/menu.xml. To add a new menu item, edit this file:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
<menu>
<add id="Your_Module::brief_module_description"
title="Your Menu Tab Title"
translate="title"
module="Your_Module"
sortOrder="10"
<!-- No parent means the tab appears in the side bar -->
parent="Magento_Catalog::inventory"
<!-- No action means the item acts as a header -->
action="path/to/your/controller"
<!-- ID of the ACL entry that validates permissions -->
resource="ACL_Entry_ID"
/>
</menu>
</config>How do you add a new tab to the Admin menu?
Do not specify a parent attribute in the <add /> node.
How are menu items related to ACL permissions?
Menu items are not shown to users with insufficient permissions to access them.
How do you add a new user with given set of permissions?
Navigate to System > Permissions > All Users in Magento admin, add a new user, and set their role under User Information > User Role.
This can also be done programmatically:
use Magento\User\Model\UserFactory;
// ...
protected $userFactory;
public function __construct(UserFactory $userFactory)
{
$this->_userFactory = $userFactory;
}
public function execute()
{
$user = $this->userFactory->create();
$user->setData(
[
'username' => 'user.name',
'firstname' => 'Forename',
'lastname' => 'Surname',
'email' => 'admin@test.com',
'password' => 'badpassword123',
'is_active' => 1
]
);
$user->setRoleId(1);
$user->save();
}| Certification | Exam Content |
|---|---|
| Associate Developer | 16% |
| Product Type | Description |
|---|---|
| Simple | A simple product is a physical item with a single SKU. Simple products have a variety of pricing and of input controls which makes it possible to sell variations of the product. Simple products can be used in association with grouped, bundle, and configurable products. |
| Configurable | A configurable product appears to be a single product with lists of options for each variation. However, each option represents a separate, simple product with a distinct SKU, which makes it possible to track inventory for each variation. |
| Grouped | A grouped product presents multiple, standalone products as a group. You can offer variations of a single product, or group them for a promotion. The products can be purchased separately, or as a group. |
| Bundle | A bundle product let customers “build their own” from an assortment of options. The bundle could be a gift basket, computer, or anything else that can be customized. Each item in the bundle is a separate, standalone product. |
| Virtual | Virtual products are not tangible products, and are typically used for products such as services, memberships, warranties, and subscriptions. Virtual products can be used in association with grouped and bundle products. |
| Downloadable | A digitally downloadable product that consists of one or more files that are downloaded. The files can reside on your server or be provided as URLs to any other server. |
| Gift Card | There are three kinds of gift cards: virtual gift cards which are sent by email, physical gift cards which are shipped to the recipient, and combined gift cards which are a combination of the two. Each has a unique code, that is redeemed during checkout. Gift cards can also be included in a grouped product. |
How would you obtain a product of a specific type?
To obtain a specific product type, build search criteria and retrieve them from the product repository:
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Bundle\Model\Product\Type;
...
public function getBundleProducts()
{
$searchCriteria = $this->searchCriteriaBuilder
->addFilter(ProductInterface::TYPE_ID, Type::TYPE_CODE)
->create();
return $this->productRepository->getList($searchCriteria)->getItems();
}What tools (in general) does a product type model provide?
The product type model is responsible for:
- Loading and configuring product options
- Preparing the product for the cart
- Processing product data to/from the database
- Checking whether the product can be sold
- Loading child products, when applicable
How do you create and manage categories?
Categories can be made in the admin panel under Category menu item and is a tree-link structure. Categories can be made programmatically using CategoryInterfaceFactory object and saving with CategoryInterfaceRepository.
How do you assign and unassign products to categories?
Navigate to Catalog > Inventory > Products in Magento Admin, select the product you wish to add to a category, and use the Categories drop down selection options to assign it to categories.
How are configurable and bundle products rendered?
view/frontend/layout/checkout_cart_item_renderers.xml define how products are rendered in the cart.
Configurable products are shown as a single line item. It is shown with the parent product's title and the simple product option selected by the customer.
Each product in the Bundle product is rendered as a single line item.
How can you create a custom shopping cart renderer?
You can customize the shopping cart by overriding with a module at vendor/module/view/frontend/layout/checkout_cart_item_renderers.xml.
The block class depends upon the Magento\Checkout\Block\Cart\Item\Renderer class and includes Actions like /Renderer/Action/Edit and /Renderer/Action/Remove.
How do you customize the shipment step of order management?
Basic steps of customizing shipping includes adding an etc/config.xml file and an etc/adminhtml/system.xml file.
In order to extend and customize shipping, you must extend \Magento\Shipping\Model\Carrier\AbstractCarrier and implement \Magento\Shipping\Model\Carrier\CarrierInterface.
How would you add another tab in the “My Account” section?
To add an additional menu tab in the customer "My Account" area create the layout file in Your_Company/Your_Module/view/frontend/layout/customer_account.xml:
<body>
<referenceContainer name="content">
<referenceBlock name="customer_account_navigation">
<block class="Magento\Customer\Block\Account\SortLinkInterface"
name="yourBlockName"
after="customer-account-navigation-address-link">
<arguments>
<argument name="label" xsi:type="string" translate="true">
Your Label
</argument>
<argument name="path" xsi:type="string">
path/to/your/module/view/
</argument>
<argument name="sortOrder" xsi:type="number">
10
</argument>
</arguments>
</block>
</referenceBlock>
</referenceContainer>
</bodyHow do you customize the order history page?
To customise the "Order History" page create the layout file in Your_Company/Your_Module/view/frontend/layout/sales_order_history.xml. The sales.order.history.info container is a common location for modifications to be made.
How do you add or modify customer attributes in a setup script?
Create Your_Company/Your_Module/Setup/UpgradeData.php with an upgrade() function:
use Magento\Customer\Model\Customer;
// ...
$attribute = $this->eavConfig->getAttribute(Customer::ENTITY, Attribute::CUSTOMER_PROMOTION_PREFERENCE);
$attribute->setData('used_in_forms', ['adminhtml_customer', 'customer_account_edit']);
$attribute->save();How do you add another field to the customer address entity using a setup script?
To add another field to customer address using a setup script, you use setup/InstallData.php while using EAV. Make sure the attribute is assigned to a form (such as customer_form_attribute table) to make sure it is saveable. The customer address field must be manually added just like other attributes.

