Magento Extensions Development

5 (1 reviews total)
By Jérémie Bouchet
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introduction to Extension Development

About this book

Magento has been revealed as the best and the most popular open source e-commerce platform in the world, with about 250k+ online stores. Magento 2 is the most recent version of this awesome toolset: every new and modern development techniques are used to offer a real modular approach and powerful architecture.

The book will support you in the writing of innovative and complex extensions. Starting from the beginning, we will cover how to set up a development environment that allows you to be really efficient in your functionality writing, including GIT registering and many other development tools. We then move on to provide a large overview of the best practices to scale your module in a high-load environment.

After these foundations, you will see how to use test driven-development (TDD) and unit tests to handle your code. We then build a complex extension together, step by step, and internationally-ready. Next, you will find out how to protect the users’ data. Finally, we will take a look a publishing the extension on the new Magento Connect marketplace and how to protect your intellectual property.

After you read this book, you will know everything you need to know to become an invaluable extension editor, whether it is for your customers’ needs or for your own requirements.

Publication date:
June 2016
Publisher
Packt
Pages
240
ISBN
9781783286775

 

Chapter 1. Introduction to Extension Development

Before I was a Magento Developer, I sold fair trade music from my own e-commerce website. Ten years ago, it was difficult to propose a technically new website to buy and download music from hundreds of artists; so much so that I spent all my time developing this part. There were a lot of other functionalities to develop, such as the customer relationship interface, the artist relationship interface, and much more; I said to myself that they would arrive later.

Later, my society, DiskOverMusic, began to organize concerts; what an exciting new challenge! Concert halls, technicians, lights, drinks, there were thousands of things to do for it. But how could I sell tickets to the millions of fans?.

Now, Magento exists and offers us a fantastic playground to develop everything our clients need in order to make the Internet innovative and secure. Standard development and the Magento framework allow you to develop clean, fast, and secure code to bring new functionalities to the community.

In our very first chapter, we will discuss the need for complex extensions in the Magento Marketplace. We will discover that marketable extensions fulfil a complex purpose.

Thanks to Magento, we will create TicketBlaster, a module which will enable a store owner to sell seated tickets to events at a venue.

Magento is an out of the box e-commerce platform with many features, such as catalog navigation, promotion rules, tax rules, reports, and order management, which enable the store owner to begin to sell his products. However, all this out of the box functionality does not allow him to differentiate his store from others, interface with third party web applications, and offer good quality marketing and social services to the customer, as well as—maybe the most important requirement—providing an answer to the specificities of the profession the store owner needs.

Thus, Magento's community, composed of hundreds of developers and editors, distribute a lot of free and paid complex extensions in the Magento Marketplace. The extensions cover usage in customer experience (gifts, social, and so on), site management (administration, automations, and so on), integrations (payment, shipping, gateways, and so on), marketing (ads, email marketing, SEO, and so on), tech utilities, and themes. We will explore the Marketplace in detail in Chapter 8. Optimization for Teamwork Development.

In this chapter, we will cover the following topics:

  • Creating an extension

  • Registering dependencies with Composer

  • Managing our work with Git source control

 

Getting started


This book assumes you have an intermediate knowledge of Magento development and installation. You will see many examples and screenshots of the Magento I use for this book; I use a local web server running with Apache (only) on an Ubuntu desktop OS.

The Magento I use is the latest beta version at the time of writing: Magento 2 C.E. version. 1.0.0-beta. That's why my local server is reachable at the following local address: http://magento2.local.com/.

My Magento admin panel is located at http://magento2.local.com/backoff.

Note

One of the first good practices is to use another admin panel URL, other than admin.

Obviously, this installation isn't recommended for a production environment, but can teach you where the main problems can appear with a web server that runs a Magento. And it is perfect for web development, because you are not limited by an Internet connection and you can immediately resolve problems.

Note

If you are interested in a production server installation, or if you have a development server in your organization, you can find a complete installation script at https://bitbucket.org/jeremie_blackbird/iams.

 

Creating an extension


When you want to create an extension, the first step is to think about its goal and functionalities. Take this important time to define and draft a prototype of the main functionalities and how they will be managed by the admin. For this step, you can use some tools available on the web, such as Proto.io, Balsamiq, or Moqups; they allow you to create and share prototypes that look and work like your extension should, but without code.

Note

Visit http://proto.io, http://balsamiq.com, and http://moqups.com to discover these useful tools.

Another step is to look at others extensions, in order to determine whether you are writing an already existing extension, that performs the same function as yours. It doesn't matter, but if this is the case, I recommend you make a better extension than the original!

Finally, open your favourite IDE and continue to read this chapter. Here, we will begin to create TicketBlaster, a module which will enables a store owner to sell seated tickets to events at a venue.

The files that handle our extension

In the following steps, we will create the files necessary to our extension:

  1. Create the extension structure by creating the following folder structure:

    • app/code/Blackbird

    • app/code/Blackbird/TicketBlaster

    • app/code/Blackbird/TicketBlaster/etc

  2. Register the extension by creating the module.xml file in the app/code/Blackbird/etc folder and add this content to it:

    <?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="Blackbird_TicketBlaster" setup_version="1.0.0" />
    </config>

    This code informs Magento that a module named TicketBlaster with the namespace Blackbird, located in the app/code/Blackbird folder can be loaded and activated.

    Note

    Blackbird is the namespace of the module; it will be visible to developers and integrators of the Magento on which it will be installed. Be sure to use a namespace which identifies you, and use this namespace for all your extensions.

  3. Open a terminal and change the directory to the Magento project root folder.

  4. Enable the module by running the two following commands:

    php bin/magento module:enable
    php bin/magento setup:upgrade
    
  5. Create the [extension_path]/registration.php file and add the following code:

    <?php
    /**
     * Copyright © 2015 Magento. All rights reserved.
     * See COPYING.txt for license details.
     */
    
    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        'Blackbird_TicketBlaster',
        __DIR__
    );
  6. You should see mentions of your new module, as in the following screenshot:

  7. You can already check that your module is taken into account by Magento by connecting to the admin and navigating to Stores| Configuration | Advanced | Advanced | Disable Modules Output:

Note

Be careful: this Configuration menu just allows disabling the output of a module and does not deactivate it.

Creating a helper

A helper will (this is not a surprise) help you and the extension during development by providing functions that execute little parts of code, such as getting a configuration value, executing generic functions for the extension, or testing the time zone.

Create a Helper class of the extension by adding the following code into the Helper [extension_path]/Helper/Event.php:

Note

From this point, we shall use [extension_path] to represent the path of our extension, which is app/code/Blackbird/TicketBlaster.

<?php

namespace Blackbird\TicketBlaster\Helper;

classEvent extends \Magento\Framework\App\Helper\AbstractHelper
{

    /**
     * Create just a useful method for our extension
     * 
     * @return bool
     */
public function justAUsefulMethod(){
        // Real code here
        // ...
return true;
    }
}

Creating a controller

Now, we will create a controller class to handle several issues. In our case, we prepare this controller in order to list all events at a venue. Moreover, controllers can get a request from the browser with parameters and dispatch it to the models of our extension.

  1. Before coding our controller, we need to create a new XML configuration file, in order to declare the new route. Create the [extension_path]/etc/frontend/routes.xml file and add the following code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
    <route id="events" frontName="events">
    <module name="Blackbird_TicketBlaster" />
    </route>
    </router>
    </config>
  2. Next, create the [extension_path]/Controller/Index/Index.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Controller\Index;
    
    class Index extends \Magento\Framework\App\Action\Action
    {
        /** @var  \Magento\Framework\View\Result\Page */
    protected $resultPageFactory;
        /**
         * @param \Magento\Framework\App\Action\Context $context
         */
    public function __construct(\Magento\Framework\App\Action\Context $context,
                                    \Magento\Framework\View\Result\PageFactory $resultPageFactory)
        {
            $this->resultPageFactory = $resultPageFactory;
            parent::__construct($context);
        }
    
        /**
         * Event Index, shows a list of recent events.
         *
         * @return \Magento\Framework\View\Result\PageFactory
         */
    public function execute()
        {
    return $this->resultPageFactory->create();
        }
    }
  3. Upgrade your Magento instance by running the following command:

    php bin/magento setup:upgrade
    

    Note

    Every time you change anything about the configuration of your extension, you will have to run this command to force Magento to handle your updates.

  4. Verify that the URL is accessible by requesting http://MAGENTO_URL/events/index/index/:

    Note

    Controllers are called by Magento when a URL is requested regarding the parameters: events corresponds to the frontName value in routes.xml, index is the name of the directory placed in the Controller folder, and index is the name of the PHP file in the Index directory. We will discover later in this chapter how controllers process requests.

Digging into these simple files

You can create this first structure at the beginning of your project, but of course, your project needs will lead you to create some other functionalities we will cover later. For now, it's just a starter. Some extensions require only controllers, others only blocks and models. Just keep in mind this simple explanation:

  • Controllers handle frontend and backend requests. They can communicate their data to models if it's needed, and eventually display data to customers or administrators.

  • Models handle data, from controllers or from a database. They are the core of your extension, do the main job, and their cap abilities are greater.

  • Blocks are here to take charge of the views: every template (.phtml file) is handled by a block that contains every necessary method for displaying data.

  • Helpers get useful core functions and can be overloaded to add some useful methods.

  • XML files, which are in the etc folder, declare the module itself and every core business configuration of our extension, and can eventually define some default values for the configuration.

  • Files that are in the Setup folder are files that create or update database tables during the installation of the extension.

Every extension comes in a single and standalone package, which will always be located in app/code/<EditorName>. In any case, you can't place your code in app/code/Magento (the core folder), because it will be overwritten when Magento is upgraded.

While writing the names of controllers and actions, make sure that they are clear and recognizable, especially by you. Their name must describe what the code does.

You can now test by yourself!

Do not hesitate to read Magento's core code, which informs you about the structure of the modules and how files work together. Make tests by using var_dump() to display text and variable values.

Tip

During all your Magento development work, use debug logs and the developer mode. These two functionalities will help you a lot and save you a lot of time! Read the http://magento.com/blog/technical/logging-approach-magento-2 page for explanations about logging; we will use it often in the up coming chapters.

 

Managing our work with Git source control


Once the project has begun, it may be a good thing to take care of code revision and eventually collaboration with other developers.

Git is a distributed revision control system developed by Linus Torvalds in 2005, initially for Linux kernel development. It has begun to replace the Subversion (SVN) system in a lot of companies, thanks to its full-fledged repository and independence from network access and a distant server.

As soon as you start to work with other people and developers, the repository must be always available on the Internet. You have two choices to do this: the first is to create a Git repository on your own server (a private server in your organization, or a rented dedicated server), and the second is to use a service that provides a repository for you. In this recipe, we will register our code on Bitbucket.

Note

GitHub and Sourceforge provide the same services, but Bitbucket offers more free services and is fully integrated with other Atlassian services such as Hipchat or Jira. It is up to you to make your choice according to your needs and environments.

Bitbucket registration

Perform the following steps for Bitbucket registration:

  1. Sign up to Bitbucket (https://bitbucket.org) by following the instructions on the website:

  2. In the upper-right corner of any page, click on Create, and then click Create repository:

  3. Enter your repository name and choose whether your repository will be public or private.

    Tip

    Check This is a private repository if you want to hide your repository from the general public, so that only selected people can see it.

  4. That's it for Bitbucket. Keep this window open for future instructions.

  5. Go to your terminal and install Git on your computer by running the following command line:

    sudo apt-get install git
    

Committing our work

In the following step, we will commit our code to a new repository, and then we will push the repository to Bitbucket:

  1. Initialize an empty repository by going to your Magento source folder and running the following command:

    git init
    
  2. Check that your repository has been created and is empty:

    git status
    
  3. Create a .gitignore file in the root of the repository and add the following content to it:

    #Git ignore for extensions writing
    /app/code/Magento/*
    /dev/tests/
    /lib/
    [...]
    

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

  4. Verify that the .gitignore file is taken into account by running git status again:

    git status
    
  5. You can see that only .gitignore is taken into account by Git.

    Note

    What happened? In fact, in a Magento project, especially with Magento CE, the source files are always available online and are the same for all. That's why you can presume that each of your collaborators first, and every client next, will run Magento. This is your code, it is unique and important, and that's why your code is the only thing to keep in your repository. Note for later: if you need to add another folder in your repository, just remove the corresponding ignore line.

  6. Run the following commands to add and commit the .gitignore file:

    git add .gitignore
    git commit .gitignore -m "Ignoring all resources files"
    
  7. Now your repository needs to be filled with the files of our project. Repeat the operation for all the files the extension needs with the command git add <folder | filename>:

    git -f add app/code/Blackbird/
    

    Note

    Note the -f option, to force Git to add the file even if it is stored in an ignored folder. If you don't use this option, Git will inform you that it can't add the file.

  8. Commit your additions:

    git commit -m "Adding the first extension files"
  9. Link your repository to the Bitbucket repository:

    git remote add originhttps://[email protected]/blackbirdagency/ticket-blaster.git
    

    Tip

    This line is to modify your repository configuration.

  10. Finally, send the files and commit comments to Bitbucket by pushing the repository:

    git push -u origin master
    

    You will find your files by clicking on your repository name on https://bitbucket.org/, proving that the files have been sent and are available for other users.

    Note

    Take note not to send useless files.

    When you are creating an extension, the people who install your code will already have a Magento instance. It is very important to share only the extension files and not Magento and customizable files, which are already modified or installed by your client.

    That's why we have chosen to ignore almost all files by default, and to force a git add with the -f option when the file we need to share is placed in an ignored folder.

Discovering other Git servers!

There are others Git storage services online, such as https://github.com/ or https://sourceforge.net/, which offer different storage spaces and different public/private repo policies.

You can create your own private Git server too, which can be dedicated to your company or organization.

 

Registering dependencies


If your module wants to override some preference values, or just change the default work of a module, you must be able to specify that your configuration must be loaded after the one you override.

In another way, your module could use some class methods defined by other modules and extensions to do its work.

We will discover dependency registering, and we are going to use it for our extension.

Discovering Composer

Composer is a package manager for PHP that provides a standard format for managing dependencies and handling complete complex installation processes. Magento 2 decided to base all platform development on Composer because it's very powerful, open source, and can manage autoloading for third party libraries and code (such as our extension).

We will now see how to use it to manage our extension and its dependencies, which are now published in a public repository on Bitbucket:

  1. Create the [extension_path]/composer.json file and add the following code:

    {
        "name": "blackbird/ticketblaster",
        "description": "Ticket manager for events",
        "type": "magento2-module",
        "version": "1.0.0",
        "license": [
            "OSL-3.0",
            "AFL-3.0"
        ],
        "require": {
            "magento/magento-composer-installer": "*",
            "magento/catalog":"*"
        },
        "extra": {
            "map": [
                [
                    "*",
                    "Blackbird/TicketBlaster"
                ]
            ]
        },
        "authors": [
            {
                "name": "Blackbird",
                "homepage": "http://black.bird.eu/",
                "role": "Developer"
            }
        ]    
    }

    Note

    The dependencies for our extension are listed in the require key.

  2. Commit and push this file to your repository.

  3. Update the main Magento 2 composer.json file by running the following command:

    composer config repositories.blackbird vcs https://bitbucket.org/blackbirdagency/ticket-blaster
    
  4. Install the extension by running the following command:

    composer require blackbird/ticketblaster
    

    Note

    This method is only recommended when you develop private projects, which are not destined to be published. Use Packagist.org registering in other cases!

Discovering packagist

https://packagist.org/ is the main and default Composer repository. It aggregates public PHP packages installable with Composer.

When you use the Composer binary to add a new extension, the first thing that Composer will do is read the main composer.json file of Magento. If your required extension isn't listed or documented, it will ask https://packagist.org/ to get more information.

In the case of TicketBlaster, the extension is published in a public Git repository and we want to share it with everyone who needs it, even if they are not familiar with Composer. The simple way for all your clients to install the extension is by runnin

  1. Create an account on https://packagist.org.

  2. Once logged in, submit your package:

    Note

    At this point, Magento 2 hasn't built its package sharing system; it will be launched in a few months.

  3. Now you just have to run the following command to install your extension:

    composer require blackbird/ticketblaster
    

    Note

    Magento 2 uses Composer to package components and product editions. This book cannot look at all the powerful functionalities of Composer, so I recommend you read the detailed explanation on http://devdocs.magento.com/guides/v2.0/extension-dev-guide/composer-integration.html, which explains how Magento and Composer work together.

 

Designing TicketBlaster – the backend


We have now a basic extension structure and its dependencies. We must now think about TicketBlaster's structure and functionalities.

One of the most important things when you propose an extension for the community is that it contains the capacity to be configurable; the more you let your clients configure the extension, the more they will use it and the less likely they are to ask you whether something is available or customizable. Think of people who don't know about code development, and think of all the Magento developers who install your extension and don't have enough time to modify it.

We first need to create and manage the events. These events should be able to be created by the administrator and listed in the frontend. Furthermore, the events will have some characteristics, such as a name, a venue, and a date. You can obviously add any field you want for your event, and make it even better by creating a specific list of venues. The event will contain every ticket available for it.

The tickets (the product the customer can buy) will be based on Magento virtual products. But we are going to slightly modify the way we will use these by creating a new product type. This new product type will allow us to link the product to an event.

Creating the table for the events

Perform the following steps to create the table:

  1. Create the [extension_path]/Setup/ folder and then create the InstallSchema.php file. Add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Setup;
    
    use Magento\Framework\Setup\InstallSchemaInterface;
    use Magento\Framework\Setup\ModuleContextInterface;
    use Magento\Framework\Setup\SchemaSetupInterface;
    use Magento\Framework\DB\Ddl\Table;
    
    class InstallSchema implements InstallSchemaInterface
    {
    [...]

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

  2. Update the Magento database by running the following command:

    php bin/magento setup:upgrade
    

    Note

    If you want to manually relaunch the SQL installation, you have to delete the table added by the module and the line corresponding to TicketBlaster in the setup_module table, then execute the preceding command again.

  3. The extension and its table are installed! To verify this, open your database interface, for instance phpMyAdmin, and go to the setup_module table:

    Note

    This table is really important; Magento uses it to check whether an extension is installed, and which version.

Creating the backend view to list the events

Once the database table has been created, we need to allow the administrator to add, update, and remove events by using the backend.

The first thing we need is a menu to access to the listing of events, so let's create the menu:

  1. Create the [extension_path]/etc/adminhtml/menu.xml file and add the following code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
    <menu>
    <add id="Blackbird_TicketBlaster::ticketblaster" title="TicketBlaster" module="Blackbird_TicketBlaster" sortOrder="50" parent="Magento_Backend::content" resource="Blackbird_TicketBlaster::ticketblaster" />
    <add id="Blackbird_TicketBlaster::ticketblaster_event" title="Events" module="Blackbird_TicketBlaster" sortOrder="0" parent="Blackbird_TicketBlaster::ticketblaster" action="ticketblaster/event" resource="Blackbird_TicketBlaster::ticketblaster_event"/>
    </menu>
    </config>

    This simple code will add the menu in the global menu of Magento, in the Content main entry:

    If you click on the menu item, you will be redirected to the dashboard, which is completely normal; we haven't created a controller to handle the request. That's what we are going to do now.

  2. Create the [extension_path]/etc/adminhtml/routes.xml file and add the following code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="admin">
    <route id="ticketblaster" frontName="ticketblaster">
    <module name="Blackbird_TicketBlaster" before="Magento_Backend" />
    </route>
    </router>
    </config>
  3. Create a new folder, [extension_path]/Controller/Adminhtml/Event, in which you create the Index.php file. Then add the following code:

    <?php
    namespace Blackbird\TicketBlaster\Controller\Adminhtml\Event;
    
    use Magento\Backend\App\Action\Context;
    use Magento\Framework\View\Result\PageFactory;
    
    class Index extends \Magento\Backend\App\Action
    {
    const ADMIN_RESOURCE = 'Blackbird_TicketBlaster::ticketblaster_event';
    
        /**
         * @var PageFactory
         */
    protected $resultPageFactory;
    
        /**
         * @param Context $context
         * @param PageFactory $resultPageFactory
         */
    public function __construct(
            Context $context,
            PageFactory $resultPageFactory
        ) {
            parent::__construct($context);
            $this->resultPageFactory = $resultPageFactory;
        }
    
        /**
         * Index action
         *
         * @return \Magento\Backend\Model\View\Result\Page
         */
    public function execute()
        {
            /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
            $resultPage = $this->resultPageFactory->create();
            $resultPage->setActiveMenu('Blackbird_TicketBlaster::ticketblaster_event');
            $resultPage->addBreadcrumb(__('Events'), __('Events'));
            $resultPage->addBreadcrumb(__('Manage Events'), __('Manage Events'));
            $resultPage->getConfig()->getTitle()->prepend(__('TicketBlaster Events'));
    
    return $resultPage;
        }
    }

    Tip

    Be careful: Magento and folder names are case-sensitive.

    The default execute() method generates the page. You will get a blank page if you click on the menu item; this is normal, and it is important to ensure you that you get this blank page before continuing. As long as you are redirected or something else, it means that your controller hasn't been read.

    Note

    From Step 4 and up to Step 20, there will be nothing to see in the backend. At most, you will have some errors and exceptions. So follow the steps strictly and test by reloading only at the end of the series.

  4. Create the [extension_path]/view/adminhtml/layout folder.

  5. Create the [extension_path]/view/adminhtml/layout/ticketblaster_event_index.xml file and add the following code:

    <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="styles"/>
    <body>
    <referenceContainer name="content">
    <uiComponent name="ticketblaster_event_listing"/>
    </referenceContainer>
    </body>
    </page>

    Note

    This code will declare the grid components to load. The filename has to correspond to <frontname>_<folder_in_controller>_<actionName>.

  6. Create the [extension_path]/view/adminhtml/ui_component/ folder.

  7. Create the [extension_path]/view/adminhtml/ui_component/ticketblaster_event_listing.xml file and add the following code:

    <?xml version="1.0" encoding="UTF-8"?>
    <listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    [...]

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

    This code generates a grid with all these functionalities:

    • dataSource: Entity source collection, which allows the loading of all the items

    • filterSearch/filters: Adds all the filters to the grid

    • massaction: Mass action declarations to manipulate items

    • paging: Pagination configuration

    • columns: Lists all the columns we want to display and their configurations, such as type, draggable, align, label, and so on

  8. Create the [extension_path]/Controller/Adminhtml/Event/AbstractMassStatus.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Controller\Adminhtml\Event;
    
    use Magento\Framework\Model\Resource\Db\Collection\AbstractCollection;
    use Magento\Framework\Controller\ResultFactory;
    
    /**
     * Class AbstractMassStatus
     */
    class AbstractMassStatus extends \Magento\Backend\App\Action
    {
    [...]

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

    This code allows us to handle our mass actions in the status field.

  9. Create the [extension_path]/Controller/Adminhtml/Event/MassDisable.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Controller\Adminhtml\Event;
    
    use Blackbird\TicketBlaster\Controller\Adminhtml\Event\AbstractMassStatus;
    
    /**
     * Class MassDisable
     */
    class MassDisable extends AbstractMassStatus
    {
        /**
         * Field id
         */
    const ID_FIELD = 'event_id';
    
        /**
         * Resource collection
         *
         * @var string
         */
    protected $collection = 'Blackbird\TicketBlaster\Model\Resource\Event\Collection';
    
        /**
         * Event model
         *
         * @var string
         */
    protected $model = 'Blackbird\TicketBlaster\Model\Event';
    
        /**
         * Event disable status
         *
         * @var boolean
         */
    protected $status = false;
    }
  10. Create the [extension_path]/Controller/Adminhtml/Event/MassEnable.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Controller\Adminhtml\Event;
    
    use Blackbird\TicketBlaster\Controller\Adminhtml\Event\AbstractMassStatus;
    
    /**
     * Class MassEnable
     */
    class MassEnable extends AbstractMassStatus
    {
        /**
         * Field id
         */
    const ID_FIELD = 'event_id';
    
        /**
         * Resource collection
         *
         * @var string
         */
    protected $collection = 'Blackbird\TicketBlaster\Model\Resource\Event\Collection';
    
        /**
         * Event model
         *
         * @var string
         */
    protected $model = 'Blackbird\TicketBlaster\Model\Event';
    
        /**
         * Event enable status
         *
         * @var boolean
         */
    protected $status = true;
    }
  11. Create the [extension_path]/Controller/Adminhtml/Event/MassDelete.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Controller\Adminhtml\Event;
    
    
    
    [...]

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

    This file handles our mass action to delete several items at the same time.

  12. Create the [extension_path]/Controller/Adminhtml/Event/Delete.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Controller\Adminhtml\Event;
    
    use Magento\Backend\App\Action;
    use Magento\TestFramework\ErrorLog\Logger;
    
    class Delete extends \Magento\Backend\App\Action
    {
    
        /**
         * @param Action\Context $context
         */
    public function __construct(Action\Context $context)
        {
            parent::__construct($context);
        }
    
        /**
         * {@inheritdoc}
         */
    protected function _isAllowed()
        {
    return $this->_authorization->isAllowed('Blackbird_TicketBlaster::ticketblaster_event_delete');
        }
    
        /**
         * Delete action
         *
         * @return \Magento\Framework\Controller\ResultInterface
         */
    public function execute()
        {
            /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
            $resultRedirect = $this->resultRedirectFactory->create();
            // check if we know what should be deleted
            $id = $this->getRequest()->getParam('event_id');
    if ($id) {
    try {
                    // init model and delete
                    $model = $this->_objectManager->create('Blackbird\TicketBlaster\Model\Event');
                    $model->load($id);
                    $model->delete();
                    // display success message
                    $this->messageManager->addSuccess(__('You deleted the event.'));
                    // go to grid
    return $resultRedirect->setPath('*/*/');
                } catch (\Exception $e) {
                    // display error message
                    $this->messageManager->addError($e->getMessage());
                    // go back to edit form
    return $resultRedirect->setPath('*/*/edit', ['event_id' => $id]);
                }
            }
            // display error message
            $this->messageManager->addError(__('We can\'t find a event to delete.'));
            // go to grid
    return $resultRedirect->setPath('*/*/');
        }
    }

    Note

    This code handles the deletion of one piece of content at a time. It will also be used in the edit page.

  13. Create the [extension_path]/Model/Event.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Model;
    
    use Blackbird\TicketBlaster\Api\Data\EventInterface;
    use Magento\Framework\Object\IdentityInterface;
    
    class Event extends \Magento\Framework\Model\AbstractModel implements EventInterface, IdentityInterface
    {
    
    [...]

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

    This code declares our model for handling our events.

  14. Create the [extension_path]/Model/Resource/Event.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Model\Resource;
    
    class Event extends \Magento\Framework\Model\Resource\Db\AbstractDb
    {
        [...]

    Note

    The source code can be found in the by-chapter branch of the Git repository, in the Chapter1 folder.

    This class declares our link between the model and the database.

  15. Create the [extension_path]/Model/Resource/Event/Collection.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Model\Resource\Event;
    
    class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
    {
        /**
         * Define resource model
         *
         * @return void
         */
    protected function _construct()
        {
            $this->_init('Blackbird\TicketBlaster\Model\Event', 'Blackbird\TicketBlaster\Model\Resource\Event');
        }
    
    }

    Note

    This code declares our collection of content of the Event type.

  16. Create the [extension_path]/Model/Event/Source/IsActive.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Model\Event\Source;
    
    class IsActive implements \Magento\Framework\Data\OptionSourceInterface {
    
        /**
         * @var \Blackbird\TicketBlaster\Model\Event
         */
    protected $_event;
    
        /**
         * Constructor
         *
         * @param \Blackbird\TicketBlaster\Model\Event $event
         */
    public function __construct(\Blackbird\TicketBlaster\Model\Event $event) {
            $this->_event = $event;
        }
    
        /**
         * Get options
         *
         * @return array
         */
    public function toOptionArray() {
            $options[] = ['label' => '', 'value' => ''];
            $availableOptions = $this->_event->getAvailableStatuses();
    foreach ($availableOptions as $key => $value) {
                $options[] = [
                    'label' => $value,
                    'value' => $key,
                ];
            }
    return $options;
        }
    
    }

    Note

    This code lists the available statuses to be used in the grid.

  17. Create the [extension_path]/Api/Data/EventInterface.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Api\Data;
    
    interface EventInterface
    {
    const EVENT_ID       = 'event_id';
    const URL_KEY       = 'url_key';
    const TITLE         = 'title';
    const VENUE         = 'venue';
    const EVENT_TIME       = 'event_time';
    const CREATION_TIME = 'creation_time';
    const UPDATE_TIME   = 'update_time';
    const IS_ACTIVE     = 'is_active';
    
    [...]

    Note

    The source code can be found in the by-chapter branch of the GIT repository, in the Chapter1 folder.

    This code lists all the methods available for an API to use in Magento. This part will be studied later in this book.

  18. Create the [extension_path]/etc/acl.xml file and add the following code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation=" urn:magento:framework:Acl/etc/acl.xsd">
    <acl>
    <resources>
    <resource id="Magento_Backend::admin">
    <resource id="Magento_Backend::content">
    <resource id="Blackbird_TicketBlaster::ticketblaster" title="TicketBlaster" sortOrder="10" >
    <resource id="Blackbird_TicketBlaster::ticketblaster_event" title="Events" sortOrder="40">
    <resource id="Blackbird_TicketBlaster::ticketblaster_event_save" title="Save" sortOrder="10" />
    <resource id="Blackbird_TicketBlaster::ticketblaster_event_delete" title="Delete" sortOrder="20" />
    </resource>
    </resource>
    </resource>
    </resource>
    </resources>
    </acl>
    </config>

    Note

    This code lists all the permissions that can be used to restrict access for specific users in the admin panel.

  19. Create the [extension_path]/etc/di.xml file and add the following code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation=" urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Blackbird\TicketBlaster\Api\Data\EventInterface" type="Blackbird\TicketBlaster\Model\Event" />
    <virtualType name="EventGridFilterPool" type="Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool">
    <arguments>
    <argument name="appliers" xsi:type="array">
    <item name="regular" xsi:type="object">Magento\Framework\View\Element\UiComponent\DataProvider\RegularFilter</item>
    <item name="fulltext" xsi:type="object">Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter</item>
    </argument>
    </arguments>
    </virtualType>
    <virtualType name="EventGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider">
    <arguments>
    <argument name="collection" xsi:type="object" shared="false">Blackbird\TicketBlaster\Model\Resource\Event\Collection</argument>
    <argument name="filterPool" xsi:type="object" shared="false">EventGridFilterPool</argument>
    </arguments>
    </virtualType>
    </config>

    Note

    This XML code declares some virtual types that provide filtered data to the grid.

  20. Create the [extension_path]/Ui/Component/Listing/Column/EventActions.php file and add the following code:

    <?php
    
    namespace Blackbird\TicketBlaster\Ui\Component\Listing\Column;
    
    use Magento\Framework\View\Element\UiComponent\ContextInterface;
    use Magento\Framework\View\Element\UiComponentFactory;
    use Magento\Ui\Component\Listing\Columns\Column;
    use Magento\Framework\UrlInterface;
    
    class EventActions extends Column
    {
        /** Url path */
    const TICKETBLASTER_URL_PATH_EDIT = 'ticketblaster/event/edit';
    const TICKETBLASTER_URL_PATH_DELETE = 'ticketblaster/event/delete';
    
        /** @var UrlInterface */
    protected $urlBuilder;
    
        /**
         * @var string
         */
    private $editUrl;
    
        /**
         * @param ContextInterface $context
         * @param UiComponentFactory $uiComponentFactory
         * @param UrlInterface $urlBuilder
         * @param array $components
         * @param array $data
         * @param string $editUrl
         */
    public function __construct(
            ContextInterface $context,
            UiComponentFactory $uiComponentFactory,
            UrlInterface $urlBuilder,
    array $components = [],
    array $data = [],
            $editUrl = self::TICKETBLASTER_URL_PATH_EDIT
        ) {
            $this->urlBuilder = $urlBuilder;
            $this->editUrl = $editUrl;
            parent::__construct($context, $uiComponentFactory, $components, $data);
        }
    
        /**
         * Prepare Data Source
         *
         * @param array $dataSource
         * @return void
         */
    public function prepareDataSource(array & $dataSource)
        {
    if (isset($dataSource['data']['items'])) {
    foreach ($dataSource['data']['items'] as & $item) {
                    $name = $this->getData('name');
    if (isset($item['event_id'])) {
                        $item[$name]['edit'] = [
                            'href' => $this->urlBuilder->getUrl($this->editUrl, ['event_id' => $item['event_id']]),
                            'label' => __('Edit')
                        ];
                        $item[$name]['delete'] = [
                            'href' => $this->urlBuilder->getUrl(self::TICKETBLASTER_URL_PATH_DELETE, ['event_id' => $item['event_id']]),
                            'label' => __('Delete'),
                            'confirm' => [
                                'title' => __('Delete "${ $.$data.title }"'),
                                'message' => __('Are you sure you wan\'t to delete a "${ $.$data.title }" record?')
                            ]
                        ];
                    }
                }
            }
        }
    }

    Note

    This class handles the action column of our grid by adding two links: delete and edit.

  21. Update Magento by running the following command:

    php bin/magento setup:upgrade
    

    Note

    This command, which we use a lot, is very important during Magento development: it clears the cache, upgrades the DB data and schema, generates interceptors and factories, and more!

    Hurrah! We can reload our page to see the grid:

 

Summary


We now have all the necessary bases for writing an efficient extension that can already do a lot of work, such as saving data and managing it. It only lacks the ability for users to manage this data, and that's exactly what we will provide in the following chapter.

Note

All the code in this book is freely available here:

https://bitbucket.org/blackbirdagency/ticket-blaster.

Do not hesitate to download it, update it, and maybe even send new modifications!

About the Author

  • Jérémie Bouchet

    Jérémie Bouchet is a French backend web developer and entrepreneur, who began his career by selling fair music. With his certification (Jérémie obtained the Magento Certified Developer certification in 2012) and his skills and knowledge of each side of the trade, Jérémie has all the keys to make a success of numerous Magento projects, by working on various complex functionalities.

    He is a cofounder of Blackbird Agency (http://black.bird.eu), a web agency specializing in Magento projects and e-commerce challenges.

    He initiated and managed other exciting projects in his city, such as a coworking space designed for web freelancers (https://quai10.org) or the http://whomadethis.site website, a web service that helps people to know who made a website.

    Browse publications by this author

Latest Reviews

(1 reviews total)
very good book for extension development and rare one also.

Recommended For You

Magento 2 Theme Design - Second Edition

Create stunning and responsive Magento 2 themes for your business

By Fernando J Miguel and 1 more
Magento 2 Development Quick Start Guide

Create an interactive online store and customize it further using Magento

By Branko Ajzele
Magento 2 Developer's Guide

Harness the power of Magento 2 – The most recent version of the world’s favourite e-Commerce platform for your online store

By Branko Ajzele
Magento 2 Beginners Guide

Discover what you need to know to build your own profitable online stores using the power of Magento 2!

By Gabriel Guarino