直接在Zou_Demo插件里开发。
一,建表
写在Zou\Demo\Setup\InstallSchema里。
因为这是插件功能默认就要的,不是后期添加的。
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Zou\Demo\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Adapter\AdapterInterface;
/**
* @codeCoverageIgnore
*/
class InstallSchema implements InstallSchemaInterface
{
/**
* {@inheritdoc}
*/
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$this->createPhysicalStores($setup);
}
protected function createPhysicalStores(SchemaSetupInterface $setup)
{
$installer = $setup;
$installer->startSetup();
/**
* Create table 'quote_donations'
*/
$table = $installer->getConnection()->newTable($installer->getTable('physical_stores'))
->addColumn(
'id',
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
null,
['identity' => true, 'nullable' => false, 'primary' => true],
'ID'
)
->addColumn(
'name',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'Name'
)
->addColumn(
'url_key',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'url_key'
)
->addColumn(
'description',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'1k',
[],
'description'
)
->addColumn(
'street',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'street'
)
->addColumn(
'postcode',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'20',
[],
'Postcode'
)
->addColumn(
'city',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'100',
[],
'City'
)
->addColumn(
'country_code',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'2',
[],
'country_code'
)
->addColumn(
'latitude',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'Latitude'
)
->addColumn(
'longitude',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'longitude'
)
->addColumn(
'phone',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'phone'
)
->addColumn(
'email',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'email'
)
->addColumn(
'opening_hours',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'1k',
[],
'opening_hours'
)
->addColumn(
'status',
\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
null,
['nullable' => true,'default' => '0'],
'status'
);
$installer->getConnection()->createTable($table);
$table = $installer->getConnection()->newTable($installer->getTable('physical_store_staff'))
->addColumn(
'id',
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
null,
['identity' => true, 'nullable' => false, 'primary' => true],
'ID'
)
->addColumn(
'store_id',
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
null,
[],
'store_id'
)
->addColumn(
'title',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'title'
)
->addColumn(
'firstname',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'firstname'
)
->addColumn(
'lastname',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'lastname'
)
->addColumn(
'phone',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'phone'
)
->addColumn(
'email',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'email'
)
->addColumn(
'image',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'255',
[],
'image'
)
->addColumn(
'status',
\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
null,
['nullable' => true,'default' => '0'],
'status'
)->addForeignKey(
$installer->getFkName('physical_store_staff', 'store_id', 'physical_stores', 'id'),
'store_id',
$installer->getTable('physical_stores'),
'id',
\Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
);
$installer->getConnection()->createTable($table);
$installer->endSetup();
}
}
这里面都是用的m2自带的建表和字段的方法。
二,建表模型
放在Model/
目录下
ResourceModel -> 资源类 真正绑定表的地方
PhysicalStore -> `physical_stores`表的资源
Collection.php -> 数据集查询
PhysicalStoreStaff -> `physical_store_staff`表的资源
Collection.php -> 数据集查询
PhysicalStore.php -> 绑定PhysicalStore模型和它的表
PhysicalStoreStaff.php -> 绑定PhysicalStoreStaff模型和它的表
PhysicalStore.php -> `physical_stores`表的模型类
PhysicalStoreStaff.php -> `physical_store_staff`表的模型类
这里面的代码和继承的类,我们不必探究,这是M2的规则,按照这种写法来写就行了。
在资源类里面绑定表名和主键。
比如physical_stores
表就在Model/ResourceModel/PhysicalStore.php
里绑定。
所谓的模型类和资源类的区别就是:
- 一个用来提供接口和方法,类似经理 给需求和功能
- 一个用来具体执行SQL,类似程序员 负责实现功能
三,后台控制器
M2中 控制器里的action都是单独文件,都放在控制器目录下。
等于说没有控制器php文件了,只有控制器下的action文件。
知识点:
- 后台控制器最终继承的是\Magento\Backend\App\Action类
- 接收post/get参数的是$this->getRequest()->getParam('id')
- 用$model->load($id)得到模型数据,以
physical_stores
表为例,$model就是Model/PhysicalStore.php。 - 用$this->_coreRegistry->register('physicalStore', $model)来缓存大数据,这样的话 在php整个生命周期内都能获取该缓存数据,也就是说在页面请求完成后 就会自动释放。跟session不一样。
四,后台页面布局
后台有4个页面,所以需要创建4个页面的布局xml
- index主页面 -> 对应控制器里的index.php
- grid列表页面 -> 对应控制器里的grid.php
- 编辑页面 -> 对应控制器里的edit.php
- 创建页面 -> 对应控制器里的new.php
因为我们是2个表,实体店信息和实体店员工信息。
所以后台有8个页面,需要创建8个页面的布局xml
physical_stores
的页面有
- index主页面 -> demoadmin_physicalstore_index.xml
- grid列表页面 -> demoadmin_physicalstore_grid.xml
- 编辑页面 -> demoadmin_physicalstore_edit.xml
- 创建页面 -> demoadmin_physicalstore_new.xml
physical_store_staff
的页面有
- index主页面 -> demoadmin_physicalstorestaff_index.xml
- grid列表页面 -> demoadmin_physicalstorestaff_grid.xml
- 编辑页面 -> demoadmin_physicalstorestaff_edit.xml
- 创建页面 -> demoadmin_physicalstorestaff_new.xml
比如index页面就是:vim view/adminhtml/layout/demoadmin_physicalstore_index.xml
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<update handle="formkey"/>
<head>
<title>PhysicalStore Manager</title>
</head>
<body>
<referenceBlock name="menu">
<action method="setActive">
<argument name="itemId" xsi:type="string">Zou_Demo::physicalStores_physicalStores</argument>
</action>
</referenceBlock>
<referenceBlock name="page.title">
<action method="setPageTitle">
<argument name="pageTitle" xsi:type="string">PhysicalStore Manager</argument>
</action>
</referenceBlock>
<referenceContainer name="content">
<block class="Zou\Demo\Block\Adminhtml\PhysicalStore" name="admin.block.physicalStore.grid.container"/>
</referenceContainer>
</body>
</page>
layout里布局文件定义好之后,还得创建对应的block文件
没啥可说的,直接按照m2的规则来写就行。
这里不需要模版文件,因为m2后台页面框架都是规定好的,继承相应的接口就行。
五,前台控制器
前台也差不多。
就2个页面,添加2个控制器方法就行了。
- 实体店列表页面 -> Zou/Demo/Controller/Physicalstore/Index.php
- 实体店详情页面(包括旗下员工信息) -> Zou/Demo/Controller/Physicalstore/View.php
前台控制器最终继承自
\Magento\Framework\App\Action\Action
类
六,前台页面布局
前台有2个页面,所以需要创建2个页面的布局xml
- index主页面 -> 对应控制器里的index.php
- view详情页面 -> 对应控制器里的view.php
view/frontend/layout/demo_physicalstore_index.xml
view/frontend/layout/demo_physicalstore_view.xml
比如demo_physicalstore_view.xml
的代码为
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Zou_Demo::css/demo.css" />
</head>
<body>
<referenceContainer name="content">
<block class="Zou\Demo\Block\Physicalstore\View" name="physicalstores.physicalstore" template="Zou_Demo::physicalstore/view.phtml"/>
</referenceContainer>
<referenceBlock name="page.main.title" remove="true" />
</body>
</page>
注意,这里有定义模版文件:Zou_Demo::physicalstore/view.phtml
。
Zou_Demo表示插件名,physicalstore/view.phtml就是插件下的模版路径。
就是在view/frontend/templates/physicalstore/view.phtml
下面
这里的templates
就是专门放模版文件的地方,它跟layout
是平级的。
自然的,我们需要创建block和phtml文件,并写代码。
block负责读取数据,类似于经典MVC框架里Controller的角色。
phtml负责输出html。类似于经典MVC框架里View的角色。
另外还定义了css文件,路径在view/frontend/web/css/demo.css
里。
针对页面的样式都写在这个css里就行。
七,添加到后台menu
m2里不是随随便便就能访问的,有严格的权限制度,所以需要手动配置下页面权限。
先添加到后台menu,再给访问权限
放在STORES
栏目下面。
1, 创建后台menu.xml文件
vim etc/adminhtml/menu.xml
<?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="Zou_Demo::physicalStores" title="Physical Store" module="Zou_Demo" sortOrder="10" resource="Zou_Demo::physicalStores" parent="Magento_Backend::stores"/>
<add id="Zou_Demo::physicalStores_physicalStores" title="Manage PhysicalStores" module="Zou_Demo" sortOrder="10" parent="Zou_Demo::physicalStores" action="demoadmin/physicalStore" resource="Zou_Demo::physicalStores_physicalStore"/>
<add id="Zou_Demo::physicalStores_PhysicalStoresStaff" title="Manage PhysicalStores Staff" module="Zou_Demo" sortOrder="10" parent="Zou_Demo::physicalStores" action="demoadmin/physicalStoreStaff" resource="Zou_Demo::physicalStores_PhysicalStoreStaff"/>
</menu>
</config>
添加了2个页面
- 实体店页面 action为demoadmin/physicalStore
- 实体店员工页面 action为demoadmin/physicalStoreStaff
2, 创建权限xml文件
vim etc/acl.xml
<?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::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Zou_Demo::config_physicalStores" title="Zou PhysicalStores" />
</resource>
</resource>
</resource>
<resource id="Zou_Demo::physicalStores" title="Physical Store" sortOrder="10">
<resource id="Zou_Demo::physicalStores_physicalStores" title="Manage PhysicalStores" sortOrder="10" />
<resource id="Zou_Demo::physicalStores_physicalStoresStaff" title="Manage PhysicalStoreStaff" sortOrder="20"/>
</resource>
</resource>
</resources>
</acl>
</config>
这里面的resource id
为menu.xml
里的add id
八,创建system.xml
system.xml 就是在后台STORES->Configuration页面设置的。
比如 启用/禁用该插件,针对该插件的一些控制选项。
在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>
<tab id="zou" translate="label" sortOrder="450">
<label>zou</label>
</tab>
<section id="demo" translate="label" type="text" sortOrder="400" showInDefault="1" showInWebsite="1" showInStore="1">
<class>separator-top</class>
<label>PhysicalStores</label>
<tab>zou</tab>
<resource>Zou_Demo::config_physicalStores</resource>
<group id="physicalstores" translate="label" type="text" sortOrder="5" showInDefault="1" showInWebsite="1" showInStore="1">
<label>PhysicalStores</label>
<field id="enabled" translate="label comment" type="select" sortOrder="0" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="custom_field1_desc" translate="label comment" type="textarea" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Custom Field #1's Description</label>
<comment><![CDATA[This will show below the Custom Field #1's input in Physical Store Add/Edit page.]]></comment>
</field>
<field id="custom_field2_desc" translate="label comment" type="textarea" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Custom Field #2's Description</label>
<comment><![CDATA[This will show below the Custom Field #2's input in Physical Store Add/Edit page.]]></comment>
</field>
</group>
<group id="implement" translate="label" type="text" sortOrder="6" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Implement Code</label>
<frontend_model>Zou\Demo\Block\Adminhtml\System\Config\Implementcode</frontend_model>
</group>
</section>
</system>
</config>
九,其他
有朋友反应说按照教程做了后 后台打不开实体店页面。
如果直接从gitee上下载插件安装 是好的。
经过排查 发现是缺少status文件和router文件。
分别是
Zou\Demo\Model\Status.php
,这是定义的公共类,便于读取status字段的option值Zou\Demo\Controller\Router.php
, 这是定义的路由重写类,在下一节会讲到。