Create a new Module
File: module.xml
#app/code/Jeff/DataTutorial/etc/Module.xml
File: registration.php
Create Simple Model - Department and Eav Model - Employee
File: Department.php
_init('Jeff\DataTutorial\Model\ResourceModel\Department'); } }
File Employee.php
#app/code/Jeff/DataTutorial/Model/Employee.php _init('Jeff\DataTutorial\Model\ResourceModel\Employee'); } }
Create ResourceModel and Collection for both Simple and Eav Model
file: Department.php
#app/code/Jeff/DataTutorial/Model/ResourceModel/Department.php _init('jeff_department', 'id'); } }
file: collection.php
#app/code/Jeff/DataTutorial/Model/ResourceModel/Department/Collection.php _init('Jeff\DataTutorial\Model\Department', 'Jeff\DataTutorial\Model\ResourceModel\Department'); } }
File: Employee.php - ResourceModel
#app/code/Jeff/DataTutorial/Model/Resource/Employee.php _read, $this->_write class properties in _construct() method */ class Employee extends AbstractEntity { protected function _construct() { $this->_read = 'jeff_employee_read'; $this->_write = 'jeff+employee_write'; } public function getEntityType() { if(empty($this->_type)) { $this->setType(\Jeff\DataTutorial\Model\Employee::ENTITY); } return parent::getEntityType(); } }
File: Collection.php - for Employee
#app/code/Jeff/DataTutorial/Model/ResourceModel/Employee/Collection.php _init( 'Jeff\DataTutorial\Model\Employee', 'Jeff\Office\Model\ResourceModel\Employee'); ); } }
Schema Installation script and upgrade script
File: InstallSchema.php
#app/code/Jeff/DataTutorial/Setup/InstallSchema.php startSetup(); $table = $setup->getConnection() ->newTable($setup->getTable('jeff_department')) ->addColumn( 'id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity'=>true, 'unsigned'=>true, 'nullable'=>false, 'primary' => true], 'Entity ID' ) ->addColumn( 'name', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 64, [], 'Name' ) ->setComment('Jeff Department Table'); $setup->getConnection()->createTable($table); $employeeEntity = \Jeff\DataTutorial\Model\Employee::ENTITY; $table = $setup->getConnection() ->newTable($setup->getTable($employeeEntity . '_entity')) ->addColumn( 'entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned'=>true, 'nullable'=>false, 'primary' => true], 'Entity Id' ) ->addColumn( 'department_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned'=>true, 'nullable'=>false], 'Department Id' ) ->addColumn( 'email', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 64, [], 'EMail' ) ->addColumn( 'first_name', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 64, [], 'First Name' ) ->addColumn( 'last_name', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 64, [], 'Last Name' ) ->setComment('Jeff_DataTutorial Employee Table'); $setup->getConnection()->createTable($table); $table = $setup->getConnection() ->newTable($setup->getTable($employeeEntity . '_entity_decimal')) ->addColumn( 'value_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity'=>true, 'nullable'=>false, 'primary'=>true], 'Value ID' ) ->addColumn( 'attribute_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Attribute Id' ) ->addColumn( 'store_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Store ID' ) ->addColumn( 'entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable'=>false, 'default'=>'0'], 'Entity Id' ) ->addColumn( 'value', \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, '12,4', [], 'value' ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_decimal', ['entity_id', 'attribute_id', 'store_id'], \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE), ['entity_id', 'attribute_id', 'store_id'], ['type'=>\Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_decimal', ['store_id']), ['store_id'] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_decimal', ['attribute_id']), ['attribute_id'] ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_decimal', 'attribute_id', 'eav_attribute', 'attribute_id' ), 'attribute_id', $setup->getTable('eav_attribute'), 'attribute_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_decimal', 'entity_id', $employeeEntity . '_entity', 'entity_id' ), 'entity_id', $setup->getTable($employeeEntity . '_entity'), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_decimal', 'store_id', 'store', 'store_id' ), 'store_id', $setup->getTable('store'), 'store_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->setComment('Employee Decimal Attribute Backend Table'); $setup->getConnection()->createTable($table); $setup->endSetup(); } }
File: UpgradeSchema.php
startSetup(); $employeeEntity = \Jeff\DataTutorial\Model\Employee::ENTITY; $departmentEntityTable = 'jeff_department'; $employeeEntityTable = $employeeEntity . '_entity'; //Adding a foreign key to department_id $setup->getConnection() ->addForeignKey( $setup->getFkName($employeeEntityTable, 'department_id', $departmentEntityTable, 'entity_id'), $setup->getTable($employeeEntityTable), 'department_id', $setup->getTable($departmentEntityTable), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ); $table = $setup->getConnection() ->newTable($setup->getTable($employeeEntity . '_entity_datetime')) ->addColumn( 'value_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity'=>true, 'nullable'=>false, 'primary'=>true], 'Value ID' ) ->addColumn( 'attribute_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Attribute Id' ) ->addColumn( 'store_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Store ID' ) ->addColumn( 'entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable'=>false, 'default'=>'0'], 'Entity Id' ) ->addColumn( 'value', \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME, null, [], 'value' ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_decimal', ['entity_id', 'attribute_id', 'store_id'], \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE), ['entity_id', 'attribute_id', 'store_id'], ['type'=>\Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_datetime', ['store_id']), ['store_id'] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_datetime', ['attribute_id']), ['attribute_id'] ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_datetime', 'attribute_id', 'eav_attribute', 'attribute_id' ), 'attribute_id', $setup->getTable('eav_attribute'), 'attribute_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_datetime', 'entity_id', $employeeEntity . '_entity', 'entity_id' ), 'entity_id', $setup->getTable($employeeEntity . '_entity'), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_datetime', 'store_id', 'store', 'store_id' ), 'store_id', $setup->getTable('store'), 'store_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->setComment('Employee Datetime Attribute Backend Table'); $setup->getConnection()->createTable($table); $table = $setup->getConnection() ->newTable($setup->getTable($employeeEntity . '_entity_text')) ->addColumn( 'value_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity'=>true, 'nullable'=>false, 'primary'=>true], 'Value ID' ) ->addColumn( 'attribute_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Attribute Id' ) ->addColumn( 'store_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Store ID' ) ->addColumn( 'entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable'=>false, 'default'=>'0'], 'Entity Id' ) ->addColumn( 'value', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 255, [], 'value' ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_text', ['entity_id', 'attribute_id', 'store_id'], \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE), ['entity_id', 'attribute_id', 'store_id'], ['type'=>\Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_text', ['store_id']), ['store_id'] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_text', ['attribute_id']), ['attribute_id'] ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_text', 'attribute_id', 'eav_attribute', 'attribute_id' ), 'attribute_id', $setup->getTable('eav_attribute'), 'attribute_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_text', 'entity_id', $employeeEntity . '_entity', 'entity_id' ), 'entity_id', $setup->getTable($employeeEntity . '_entity'), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_text', 'store_id', 'store', 'store_id' ), 'store_id', $setup->getTable('store'), 'store_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->setComment('Employee text Attribute Backend Table'); $setup->getConnection()->createTable($table); $table = $setup->getConnection() ->newTable($setup->getTable($employeeEntity . '_entity_int')) ->addColumn( 'value_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity'=>true, 'nullable'=>false, 'primary'=>true], 'Value ID' ) ->addColumn( 'attribute_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Attribute Id' ) ->addColumn( 'store_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Store ID' ) ->addColumn( 'entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable'=>false, 'default'=>'0'], 'Entity Id' ) ->addColumn( 'value', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, [], 'value' ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_int', ['entity_id', 'attribute_id', 'store_id'], \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE), ['entity_id', 'attribute_id', 'store_id'], ['type'=>\Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_int', ['store_id']), ['store_id'] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_int', ['attribute_id']), ['attribute_id'] ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_int', 'attribute_id', 'eav_attribute', 'attribute_id' ), 'attribute_id', $setup->getTable('eav_attribute'), 'attribute_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_int', 'entity_id', $employeeEntity . '_entity', 'entity_id' ), 'entity_id', $setup->getTable($employeeEntity . '_entity'), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_int', 'store_id', 'store', 'store_id' ), 'store_id', $setup->getTable('store'), 'store_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->setComment('Employee Int Attribute Backend Table'); $setup->getConnection()->createTable($table); $table = $setup->getConnection() ->newTable($setup->getTable($employeeEntity . '_entity_varchar')) ->addColumn( 'value_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity'=>true, 'nullable'=>false, 'primary'=>true], 'Value ID' ) ->addColumn( 'attribute_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Attribute Id' ) ->addColumn( 'store_id', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['unsigned'=>true, 'nullable'=>false, 'default'=>'0'], 'Store ID' ) ->addColumn( 'entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable'=>false, 'default'=>'0'], 'Entity Id' ) ->addColumn( 'value', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 256, [], 'value' ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_varchar', ['entity_id', 'attribute_id', 'store_id'], \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE), ['entity_id', 'attribute_id', 'store_id'], ['type'=>\Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_varchar', ['store_id']), ['store_id'] ) ->addIndex( $setup->getIdxName($employeeEntity . '_entity_varchar', ['attribute_id']), ['attribute_id'] ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_varchar', 'attribute_id', 'eav_attribute', 'attribute_id' ), 'attribute_id', $setup->getTable('eav_attribute'), 'attribute_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_varchar', 'entity_id', $employeeEntity . '_entity', 'entity_id' ), 'entity_id', $setup->getTable($employeeEntity . '_entity'), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->addForeignKey( $setup->getFkName( $employeeEntity . '_entity_varchar', 'store_id', 'store', 'store_id' ), 'store_id', $setup->getTable('store'), 'store_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->setComment('Employee Varchar Attribute Backend Table'); $setup->getConnection()->createTable($table); $setup->endSetup(); } }
Data Installation script and upgrade script
InstallData.php:
#app/code/Jeff/DataTutorial/Setup/InstallData.php; employeeSetupFactory = $employeeSetupFactory; } public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $employeeEntity = \Jeff\DataTutorial\Model\Employee::ENTITY; $employeeSetup = $this->employeeSetupFactory->create(['setup' => $setup]); $employeeSetup->installEntities(); /* Add attributes for the employee entity Using the addAttribute method on the instance of \Jeff\DataTutorial\Setup\EmployeeSetupFactory, we are instructing Magento to add a number of attributes to its entity. Within addAttribute method, there is a call to the $this->attributeMapper->map($attr, $entityTypeId) method. attributeMapper conforms to Magento\Eav\Model\Entity\Setup\PropertyMapperInterface, which looking at vendor/magento/module-eav/etc/di.xml has a preference for the Magento\Eav\Model\Entity\Setup\PropertyMapper\Composite class, which further initailize the following mapper classes: 1) Magento\Eav\Model\Entity\Setup\PropertyMapper 2) Magento\Customer\Model\ResourceModel\Setup\PropertyMapper 3) Magento\Catalog\Model\ResourceModel\Setup\PropertyMapper 4) Magento\ConfigurableProduct\Model\ResourceModel\Setup\PropertyMapper Since we are defining our own entity types, the mapper class we are mostly interested in is Magento\Eav\Model\Entity\Setup\PropertyMapper. The key strings match the column names in the eav_attribute table, while the value strings match the keys of our array passed to the addAttriubte method of within InstallData.php */ $employeeSetup->addAttribute( $employeeEntity, 'service_years', ['type' => 'int'] ); $employeeSetup->addAttribute( $employeeEntity, 'dob', ['type' => 'datetime'] ); $employeeSetup->addAttribute( $employeeEntity, 'salary', ['type' => 'decimal'] ); $employeeSetup->addAttribute( $employeeEntity, 'vat_number', ['type' => 'varchar'] ); $employeeSetup->addAttribute( $employeeEntity, 'not', ['type' => 'text'] ); $setup->endSetup(); } }
UpgradeData.php
#app/code/Jeff/DataTutorial/Setup/UpgradeData.php; departmentFactory = $departmentFactory; $this->employeeFactory = $employeeFactory; } public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $salesDepartment = $this->departmentFactory->create(); $salesDepartment->setName('Sales'); $salesDepartment->save(); $employee = $this->employeeFactory->create(); $employee->setDepartmentId($salesDepartment->getId()); $employee->setEmail('jyu@dummy.com'); $employee->setFirstName('Jeff'); $employee->setLastName('Yu'); $employee->setServiceYears(3); $employee->setDob('1999-01-01'); $employee->setSalary('5400.00'); $employee->setVatNumber('GB12345678'); $employee->setNote('Just some notes to Jeff'); $employee->save(); $setup->endSetup(); } }
EmployeeSetup.php
[ 'entity_model' => 'Jeff\DataTutorial\Model\ResourceModel\Employee', //the full resource model class name 'table' => $employeeEntity . '_entity', 'attributes' => [ 'department_id' => [ 'type' => 'static', ], 'email' => [ 'type' => 'static', ], 'first_name' => [ 'type' => 'static', ], 'last_name' => [ 'type' => 'static', ], ], ], ]; return $entities; } }
Last step
Run following commands to install new module and models :
php bin/magento module:enable Jeff_DataTutorial php bin/magento setup:upgrade php bin/magento cache:clean
Get the source code GitHub.
Note: when you try to install this module and you encounter following error, please disable the EAV cache
[PDOException] There is no active transaction