BoxLeaf_HelloWorld disabled

Magento 2 – Development – Part 2: Creating a new module

This article will go the process and requirements of creating a new Magento 2 module. There are allot of articles out there discussing creating your first module that’s because there is a number of ways of doing this and each Developer has there own preference for manageability. At boxleaf Digital this is our preferred way to make code manageable.

Where can Magento 2 modules live?

When using modules Magento 2 advocates using the vendor/vendor-name/module-name directories. This is the directory composer installs all the modular components of the Magento 2 core, and any third party modules.  For more information on composer read our article on composer basics here.

Since this is the composer location its never recommended to modify any code within the vendor directory, as when composer update is ran this would be overwritten..

And if you are working on Magento 2 Cloud Pro, Or Magento 2 Cloud starter, the code from vendor would not be committed. If you was to commit the code it would be overwritten during the deployment process. On either IaaS or SaaS services. As both of these deployment methods run the composer update command.

  • Infrastructure as a service (IaaS) are online services that provide high-level APIs used to de-reference various low-level details of underlying network infrastructure like physical computing resources, location, data partitioning, scaling, security, backup etc.
  • Software as a service (SaaS) is a software licensing and delivery model in which software is licensed on a subscription basis and is centrally hosted. It is sometimes referred to as “on-demand software”.
So where else can we develop locally where the code base wont be overwritten?

Well like magento 1 where code was stored in app/code/core which in magento 2 has become vendor/magento/ directories. But in Magento 1 we also had app/code/community and app/code/local these are the custom modules for magento 1.

So can we have magento 2 modules in the same place?

Not quite we can not but the app/code directory does still exist, and this is where you should be developing your custom modules. With exactly the same format as the vendor directory, so we would end up with a path such as app/code/vendor-name/module-name.

But lets assume for a second you want to deploy your module and share it, and to test it you composer require your new module from a git repository. What would happen then?

Well to put it simply as this is a topic for another day, you would get the code base already exists error, as the module would exist in two places, unless you use the composer replace key.

Whats boxleafs Preference ?

As a developer i decided to mix a use of developing locally and composer. Doing so by creating a complete custom directory  in the root of magento 2 called custom-modules, and in here we develop our modules. We will discuss this more late.

Creating a new module.

The first thing we are going to do is create the custom directory in the root of our magento 2 instance. As mentioned i dont like to work in app/code as it has a way of causing problems by forgetting something simple as a replace key in composer.json. And we are going to then create a subdirectory called BoxLeaf this will be our vendor name. We are going to create a simple HelloWorld module. So our module path will be custom/BoxLeaf/HelloWorld.

Magento 2 module requirements.

All magento 2 modules, require three main files for a module to be considered a module.Within the HelloWorld module we will create:

  • composer.json
  • etc/module.xml
  • registration.php

A handy tip: One of the magento 2 exam questions resolve around creating custom modules and the three required files to do.

composer.json is what tells the dependency management system what our module is; and how to register the module with the autoloader.

module.xml is what declares and names your module component using URN schema validation to make sure your XML is valid.

registration.php finally this file is called by composer.json PSR to tell magento 2 what type of component you are loading and how to locate the module.

Creating the files

Lets start by creating composer.json with the below content.

{
  "name": "boxleaf/module-helloworld",
  "description": "Simple hello world magento 2 module",
  "type": "magento2-module",
  "authors": [
    {
      "name": "Daniel Coull",
      "email": "hello@boxleafdigital.com",
      "homepage": "https://www.boxleafdigital.com",
      "role": "Developer"
    }
  ],
  "version": "1.0.0",
  "license": [
    "OSL-3.0",
    "AFL-3.0"
  ],
  "require": {
    "php": "~7.0|~7.1.3|~7.2|~7.3"
  },
  "autoload": {
    "files": [ "registration.php" ],
    "psr-4": {
      "BoxLeaf\\HellowWorld\\": ""
    }
  }
}
So whats within this composer.json.

We started by naming our composer component "name": "boxleaf/module-helloworld" using the name key followed by a vendor/modulename type name you can see we also prefixed our module name with module- this just keeps things tidy and easy to tell what it is we could use theme- or locale-. Or anything easier to tell what it is. From here we have used the "description" key though you don’t have to have this field its good to tell composer what it is if you was to deploy your code to packagist.

We then need to add the required * "type" key this is what tells composer the type of component it is. In this case its a module so its defined as magento2-module again this could be locale or theme.

The next required key is the "version" key used as part of the dependency management and to lock the module to the version.

Finally our required section is the "autoload" key wi thin this section we start with “files”, this points composer to use registration.php to set its autoloader path. Followed by the psr-4 key this states we will use the psr-4 namespacing standard, and the namespace that will be used for all PHP classes within our module.

All the other schema keys throughout are here to provide constraints to our module, and for keeping things tidy and populated for packagist.

Now we need to write our module.xml

Firstly il take a detour back to the URN validation scheme, that is used to validate all of the XML config files across magento2. If your using the PHPStorm IDE to develop your code you may want to make PHPStorm pick up the URN paths. Magento provides a handy Command Line command to help us with this.  If you don’t use PHPStorm you can skip this section.

You want to enter the below command into a terminal window, this will generate the URN paths for your IDE.

$ php bin/magento dev:urn-catalog:generate ./idea/misc.xml

Generate URN paths

Now you have a validator path generated we can go and add the following to etc/module.xml.

<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="BoxLeaf_HelloWorld"/>
</config>

Within our config you can see we set xsi:noNamespaceSchemaLocation and set the path for the urn validator to “urn:magento:framework:Module/etc/module.xsd” this tells magento to look for the schema validator to vendor/magento/framework/Module/etc/module.xsd. This xsd tells the xml which fields it can have within the scope of the defined xml.

We have then added <module name="BoxLeaf_HelloWorld"/> where the name is VendorName_ModuleName

This is the single inline module field, but lets assume we need to have our module dependent on another magento 2 module such as backend or framework. We can set this requirment in the composer.json but we also have to tell magento 2 that our module needs to load after a specific module.

For this we can modify our xml to like below, using the sequence tag.

<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="BoxLeaf_HelloWorld">
        <sequence>
            <!-- BoxLeaf_HelloWorld is dependent on Magento_Backend: -->
            <module name="Magento_Backend" />
        </sequence>
    </module>
</config>

As shown we have opened the module tag instead of self closing and added a sequence followed by another module.

The final file we need is the registration.php

<?php
use \Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'BoxLeaf_HelloWorld', __DIR__);

All we have done is told PHP to use the class use \Magento\Framework\Component\ComponentRegistrar then return the register static function. Passing in the ComponentRegistrar::MODULE static constant which returns ‘module’. Telling magento 2 we are registering a module.

If this was a theme we was registering we could have set it to ComponentRegistrar::THEME or if it was a language it could have been ComponentRegistrar::LANGUAGE.

The second paramater we pass is the VendorName_ModuleName this needs to match the name from our module.xml. If this was a theme our second parameter would be ‘area/vendor/theme name’ where area is either frontend or adminhtml. The third and final parameter is __DIR__ this is our code path we are telling it to use the global constant __DIR__ which is our current directory.

This concludes the actual creation of our base module, but as we did not use app/code this will not automatically get registered. We now need to symlink how module to vendor using composer. From the root magento directory enter the below into the terminal.

composer config repositories.helloworld path custom/BoxLeaf/HelloWorld &&
composer require boxleaf/module-helloworld:1.0.0 &&
composer update

What we did above was told composer to add a new repository in the Magento 2 composer.json, we called it hello world. Telling composer it was a path repository and gave it the directory to look. After we told composer to require our module, and then update.

Composer install Magento 2 Module from path

Composer install Magento 2 Module from path

Testing our Magento 2 module

With our symlinked module, we need to test Magento can see our module, and then install it  at this point its mostly Command Line tools using magento 2 bin/magento command.  For this we can use the below command:

php bin/magento module:status

You should notice this return our new module under the disabled section.

BoxLeaf_HelloWorld disabled

So now we can go ahead and enable our module running

php bin/magento module:enable BoxLeaf_HelloWorld

BoxLeaf_HelloWorld enabled module

If you was to run module:status now you should no longer see it as disabled but in the enabled section. But as the terminal response says we have one final command to run:

php bin/magento setup:upgrade && php bin/magento setup:di:compile

This tells magento 2 to run through all its setup scripts, though ours has none, followed by telling magento to recompile its code base.  If your in developer mode the below command is irrelevant but if your in production you will need to rerun static content, like below otherwise your site will have no styles and numerous JavaScript errors.

To find out what mode your magento 2 instance is in run the following first.

php bin/magento deploy:mode:show

This will run either default, developer, production.

php bin/magento setup:static-content:deploy en_GB en_US

That’s all you need you now have a base plate to start developing your module, in the next article we will start with developing blocks to modify the frontend.   If you have any questions leave them below and i shall get back to you in due course.

 

Send us a Skype message

boxleafdigital

Call boxleaf Digital