Doctrine/ExtJS:如何基于第三方模型创建自定义模型并关联商品
我之前处理过类似的Shopware插件定制需求,先梳理下你的核心痛点:第三方Ktype插件的数据表没有和Shopware商品表建立外键关联,仅靠商品的文本字段存储关联的Ktype编号;现在要在商品详情页的自定义标签页里实现带复选框的可排序列,加载时自动勾选已关联的Ktype,变更后能保存新的关联关系。下面是几个针对性的解决方案:
思路1:扩展ExtJS Store/Model,动态添加selected字段(无需改动数据库)
这个方案不需要新建自定义模型或数据库表,直接在前端ExtJS层面处理,既解决复选框状态,又支持排序。
步骤1:扩展第三方Ktype的ExtJS Model
在你的自定义插件里,创建一个扩展自第三方插件Model的自定义Model,添加selected字段:
// 假设第三方Model是'KtypePlugin\Model\Ktype' Ext.define('YourPlugin\Model\CustomKtype', { extend: 'KtypePlugin\Model\Ktype', fields: [ { name: 'selected', type: 'boolean', defaultValue: false } ] });
步骤2:配置Store并加载时设置勾选状态
在你的商品详情标签页的Store配置中,使用自定义Model,并且在Store加载完成后,根据当前商品的ktypes文本字段匹配设置selected状态:
Ext.define('YourPlugin\Store\KtypeSelection', { extend: 'Shopware.store.Listing', model: 'YourPlugin\Model\CustomKtype', remoteSort: true, // 支持远程排序 proxy: { type: 'ajax', url: '{url controller="YourPlugin" action="getKtypes"}', reader: { type: 'json', rootProperty: 'data' } }, listeners: { load: function(store, records) { // 获取当前商品的Ktype文本字段(假设商品数据存在record变量中) const currentArticleKtypes = record.get('ktypes').split(','); records.forEach(record => { if (currentArticleKtypes.includes(record.get('ktype_number'))) { record.set('selected', true); } }); } } });
步骤3:在Grid中添加可排序的复选框列
在你的自定义标签页Grid里,添加selected列,设置sortable: true,并且绑定复选框:
{ xtype: 'gridcolumn', dataIndex: 'selected', text: '{s name="selected"}Selected{/s}', width: 80, sortable: true, renderer: function(value, metaData, record) { return `<input type="checkbox" ${value ? 'checked' : ''} onclick="Ext.ComponentQuery.query('your-plugin-ktype-grid')[0].handleCheckboxClick(this, '${record.get('ktype_number')}')">`; } }
步骤4:保存选中的Ktype到商品字段
添加保存按钮的点击事件,收集所有选中的Ktype编号,拼接成文本后更新商品的ktypes字段:
handleSave: function() { const grid = this.down('your-plugin-ktype-grid'); const selectedKtypes = grid.getStore().queryBy(record => record.get('selected')).getRange().map(r => r.get('ktype_number')); const articleRecord = this.record; // 当前商品的Record articleRecord.set('ktypes', selectedKtypes.join(',')); articleRecord.save({ success: function() { Shopware.Notification.createGrowlMessage( '{s name="successTitle"}Success{/s}', '{s name="successMessage"}Ktype associations saved{/s}' ); } }); }
思路2:创建Doctrine中间关联表(长期优化方案)
如果希望从数据库层面建立关联,解决后续扩展问题,可以创建一个中间表,关联商品ID和Ktype编号,手动同步现有数据。
步骤1:创建中间表实体
在你的插件中创建一个ArticleKtype实体:
// YourPlugin/src/Entity/ArticleKtype.php namespace YourPlugin\Entity; use Shopware\Core\Content\Product\ProductDefinition; use Doctrine\ORM\Mapping as ORM; use Shopware\Core\Framework\DataAbstractionLayer\Entity; use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait; /** * @ORM\Entity * @ORM\Table(name="your_plugin_article_ktype") */ class ArticleKtype extends Entity { use EntityIdTrait; /** * @ORM\Column(name="article_id", type="string", length=36) */ protected string $articleId; /** * @ORM\Column(name="ktype_number", type="string", length=255) */ protected string $ktypeNumber; // Getters and Setters public function getArticleId(): string { return $this->articleId; } public function setArticleId(string $articleId): void { $this->articleId = $articleId; } public function getKtypeNumber(): string { return $this->ktypeNumber; } public function setKtypeNumber(string $ktypeNumber): void { $this->ktypeNumber = $ktypeNumber; } }
步骤2:同步现有商品的Ktype数据
编写一个命令或脚本,将现有商品ktypes字段中的编号同步到中间表:
// 示例同步代码(可放在插件安装时执行) $products = $this->productRepository->search(new Criteria(), $context)->getEntities(); foreach ($products as $product) { $ktypes = explode(',', $product->getCustomFields()['ktypes'] ?? ''); // 假设存在自定义字段或商品字段中 foreach ($ktypes as $ktype) { if (trim($ktype)) { $articleKtype = new ArticleKtype(); $articleKtype->setArticleId($product->getId()); $articleKtype->setKtypeNumber(trim($ktype)); $this->articleKtypeRepository->create([$articleKtype->jsonSerialize()], $context); } } }
步骤3:ExtJS层面关联中间表数据
此时你的ExtJS Store可以从中间表获取当前商品已选中的Ktype,加载时直接设置selected状态,保存时直接操作中间表(新增/删除关联),同时支持排序,因为selected状态可以通过关联查询返回,或者在Store中处理。
关键注意事项
- 如果选择思路1,要注意
selected字段是前端动态添加的,排序时需要在后端处理:当排序字段是selected时,后端查询Ktype数据时,根据当前商品的关联情况返回排序后的结果。 - 思路2需要考虑数据同步的一致性,比如商品
ktypes字段更新时,也要同步中间表,或者后续废弃ktypes文本字段,完全用中间表关联。
内容的提问来源于stack exchange,提问作者Stefan Schulte

