官术网_书友最值得收藏!

Creating a miniature module

For the purpose of this chapter, we will create a miniature module called Foggyline_Office.

The module will have two entities defined as follows:

  • Department: a simple model with the following fields:
    • entity_id: primary key
    • name: name of department, string value
  • Employee: an EAV model with the following fields and attributes:
    • Fields:
      • entity_id: primary key
      • department_id: foreign key, pointing to Department.entity_id
      • email: unique e-mail of an employee, string value
      • first_name: first name of an employee, string value
      • last_name: last name of an employee, string value
    • Attributes:
      • service_years: employee's years of service, integer value
      • dob: employee's date of birth, date-time value
      • salary – monthly salary, decimal value
      • vat_number: VAT number, (short) string value
      • note: possible note on employee, (long) string value

Every module starts with the registration.php and module.xml files. For the purpose of our chapter module, let's create the app/code/Foggyline/Office/registration.php file with content as follows:

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Foggyline_Office',
    __DIR__
);

The registration.php file is sort of an entry point to our module.

Now let's create the app/code/Foggyline/Office/etc/module.xml file with the following content:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/ etc/module.xsd">
    <module name="Foggyline_Office" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Eav"/>
        </sequence>
    </module>
</config>

We will get into more details about the structure of the module.xml file in later chapters. Right now, we will only focus on the setup_version attribute and module element within sequence.

The value of setup_version is important because we might use it within our schema install script (InstallSchema.php) files, effectively turning the install script into an update script, as we will show soon.

The sequence element is Magento's way of setting dependencies for our module. Given that our module will make use of EAV entities, we list Magento_Eav as a dependency.

Creating a simple model

The Department entity, as per requirements, is modeled as a simple model. We previously mentioned that whenever we talk about models, we implicitly think of model class, resource class, and collection class forming one unit.

Let's start by first creating a model class, (partially) defined under the app/code/Foggyline/Office/Model/Department.php file as follows:

namespace Foggyline\Office\Model;

class Department extends \Magento\Framework\Model\AbstractModel
{
    protected function _construct()
    {
        $this-> _init('Foggyline\Office\Model \ResourceModel\Department');
    }
}

All that is happening here is that we are extending from the \Magento\Framework\Model\AbstractModel class, and triggering the $this->_init method within _construct passing it our resource class.

The AbstractModel further extends \Magento\Framework\Object. The fact that our model class ultimately extends from Object means that we do not have to define a property name on our model class. What Object does for us is that it enables us to get, set, unset, and check for a value existence on properties magically. To give a more robust example than name, imagine our entity has a property called employee_average_salary in the following code:

$department->getData('employee_average_salary');
$department->getEmployeeAverageSalary();

$department->setData('employee_average_salary', 'theValue');
$department->setEmployeeAverageSalary('theValue');

$department->unsetData('employee_average_salary');
$department->unsEmployeeAverageSalary();

$department->hasData('employee_average_salary');
$department->hasEmployeeAverageSalary();

The reason why this works is due to Object implementing the setData, unsetData, getData, and magic __call methods. The beauty of the magic __call method implementation is that it understands method calls like getEmployeeAverageSalary, setEmployeeAverageSalary, unsEmployeeAverageSalary, and hasEmployeeAverageSalary even if they do not exist on the Model class. However, if we choose to implement some of these methods within our Model class, we are free to do so and Magento will pick it up when we call it.

This is an important aspect of Magento, sometimes confusing to newcomers.

Once we have a model class in place, we create a model resource class, (partially) defined under the app/code/Foggyline/Office/Model/ResourceModel/Department.php file as follows:

namespace Foggyline\Office\Model\ResourceModel;

class Department extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
    protected function _construct()
    {
        $this->_init('foggyline_office_department', 'entity_id');
    }
}

Our resource class that extends from \Magento\Framework\Model\ResourceModel\Db\AbstractDb triggers the $this->_init method call within _construct. $this->_init accepts two parameters. The first parameter is the table name foggyline_office_department, where our model will persist its data. The second parameter is the primary column name entity_id within that table.

AbstractDb further extends Magento\Framework\Model\ResourceModel\AbstractResource.

Note

The resource class is the key to communicating to the database. All it takes is for us to name the table and its primary key and our models can save, delete, and update entities.

Finally, we create our collection class, (partially) defined under the app/code/Foggyline/Office/Model/ResourceModel/Department/Collection.php file as follows:

namespace Foggyline\Office\Model\ResourceModel\Department;

class Collection extends \Magento\Framework\Model\ResourceModel \Db\Collection\AbstractCollection
{
    protected function _construct()
    {
        $this->_init(
            'Foggyline\Office\Model\Department',
            'Foggyline\Office\Model\ResourceModel\Department'
        );
    }
}

The collection class extends from \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection and, similar to the model and resource classes, does a $this->_init method call within _construct. This time, _init accepts two parameters. The first parameter is the full model class name Foggyline\Office\Model\Department, and the second parameter is the full resource class name Foggyline\Office\Model\ResourceModel\Department.

AbstractCollection implements Magento\Framework\App\ResourceConnection\SourceProviderInterface, and extends \Magento\Framework\Data\Collection\AbstractDb. AbstractDb further extends \Magento\Framework\Data\Collection.

It is worth taking some time to study the inners of these collection classes, as this is our go-to place for whenever we need to deal with fetching a list of entities that match certain search criteria.

Creating an EAV model

The Employee entity, as per requirements, is modeled as an EAV model.

Let's start by first creating an EAV model class, (partially) defined under the app/code/Foggyline/Office/Model/Employee.php file as follows:

namespace Foggyline\Office\Model;

class Employee extends \Magento\Framework\Model\AbstractModel
{
    const ENTITY = 'foggyline_office_employee';

    public function _construct()
    {
        $this-> _init('Foggyline\Office \Model \ResourceModel\Employee');
    }
}

Here, we are extending from the \Magento\Framework\Model\AbstractModel class, which is the same as with the simple model previously described. The only difference here is that we have an ENTITY constant defined, but this is merely syntactical sugar for later on; it bears no meaning for the actual model class.

Next, we create an EAV model resource class, (partially) defined under the app/code/Foggyline/Office/Model/ResourceModel/Employee.php file as follows:

namespace Foggyline\Office\Model\ResourceModel;

class Employee extends \Magento\Eav\Model\Entity\AbstractEntity
{

    protected function _construct()
    {
        $this->_read = 'foggyline_office_employee_read';
        $this->_write = 'foggyline_office_employee_write';
    }

    public function getEntityType()
    {
        if (empty($this->_type)) {
            $this->setType(\Foggyline\Office\Model \Employee::ENTITY);
        }
        return parent::getEntityType();
    }
}

Our resource class extends from \Magento\Eav\Model\Entity\AbstractEntity, and sets the $this->_read, $this->_write class properties through _construct. These are freely assigned to whatever value we want, preferably following the naming pattern of our module. The read and write connections need to be named or else Magento produces an error when using our entities.

The getEntityType method internally sets the _type value to \Foggyline\Office\Model\Employee::ENTITY, which is the string foggyline_office_employee. This same value is what's stored in the entity_type_code column within the eav_entity_type table. At this point, there is no such entry in the eav_entity_type table. This is because the install schema script will be creating one, as we will be demonstrating soon.

Finally, we create our collection class, (partially) defined under the app/code/Foggyline/Office/Model/ResourceModel/Employee/Collection.php file as follows:

namespace Foggyline\Office\Model\ResourceModel\Employee;

class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
{
    protected function _construct()
    {
        $this->_init('Foggyline\Office\Model\Employee', 'Foggyline\Office\Model\ResourceModel\Employee');
    }
}

The collection class extends from \Magento\Eav\Model\Entity\Collection\AbstractCollection and, similar to the model class, does a $this->_init method call within _construct. _init accepts two parameters: the full model class name Foggyline\Office\Model\Employee, and the full resource class name Foggyline\Office\Model\ResourceModel\Employee.

AbstractCollection has the same parent tree as the simple model collection class, but on its own it implements a lot of EAV collection-specific methods like addAttributeToFilter, addAttributeToSelect, addAttributeToSort, and so on.

Note

As we can see, EAV models look a lot like simple models. The difference lies mostly in the resource class and collection class implementations and their first level parent classes. However, we need to keep in mind that the example given here is the simplest one possible. If we look at the eav_entity_type table in the database, we can see that other entity types make use of attribute_model, entity_attribute_collection, increment_model, and so on. These are all advanced properties we can define alongside our EAV model making it closer to the implementation of the catalog_product entity type, which is probably the most robust one in Magento. This type of advanced EAV usage is out of the scope of this book as it is probably worth a book on its own.

Now that we have simple and EAV models in place, it is time to look into installing the necessary database schema and possibly pre-fill it with some data. This is done through schema and data scripts.

主站蜘蛛池模板: 永嘉县| 邯郸县| 霸州市| 徐水县| 华亭县| 若尔盖县| 密云县| 寿光市| 九龙县| 东城区| 濉溪县| 新密市| 探索| 汾西县| 青阳县| 万年县| 正定县| 治多县| 密云县| 囊谦县| 滦南县| 滁州市| 林州市| 洪湖市| 广西| 嵊泗县| 奉化市| 太仆寺旗| 湖南省| 大埔县| 黔江区| 巴林右旗| 钦州市| 新建县| 中牟县| 泾阳县| 宁波市| 尚志市| 丁青县| 蓝山县| 甘南县|