Почему TreeStore.sync () не записывает в базу данных?

Мне было поручено расширить и изменить плагин Shopware. Оригинальный автор больше не в компании. До этого я никогда не имел дело с Shopware и ExtJs.
Поэтому я провожу последние пару дней, чтобы понять себя, и думаю, что до сих пор понял принципы и парадигму.

Единственное, с чем у меня сейчас проблемы, это следующая проблема:

У меня есть Ext.tree.Panel который я хочу сохранить в базе данных с помощью Ajax. Узел добавляется в дерево, я вижу его в графическом интерфейсе. Но после звонка optionsTree.getStore().sync() в базе данных ничего не поступает. createProductOptionAction() в PHP контроллер не вызывается, но я не могу понять, почему. В журнале консоли браузера нет сообщений об ошибках, в файлах журналов Shopware нет сообщений об ошибках. Ничего такого. Кажется, все работает нормально. Но данные не хранятся.

Оригинальный плагин имел Ext.grid.Panel хранить и отображать данные. И это прекрасно работает. Но после изменения на Ext.tree.Panel и изменение кода, он больше не работает. С моей точки зрения это должно работать. Но это не так, и я не вижу своих ошибок.

Любая помощь действительно ценится, я все еще чертовски новичок в ExtJs. 🙂

Вот что у меня так далеко:

app.js

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager', {

extend:'Enlight.app.SubApplication',
name:'Shopware.apps.CCBConfigurablePhotoProductsManager',

bulkLoad: true,
loadPath:'{url controller="CCBConfigurablePhotoProductsManager" action="load"}',

controllers:['ProductConfigurator'],
stores:['ProductOptionsList'],
models:['ProductOption'],
views: ['ProductOptions', 'Window' ],

launch: function() {
var me = this,
mainController = me.getController('ProductConfigurator');
return mainController.mainWindow;
}
});

Контроллер / controller.js

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager.controller.ProductConfigurator', {

extend:'Ext.app.Controller',

refs: [
{ ref: 'productOptionsTree', selector: 'product-configurator-settings-window product-options-tree' }
],

init:function () {
var me = this;

me.mainWindow = me.createMainWindow();
me.addControls();
me.callParent(arguments);

return me.mainWindow;
},

addControls: function() {
var me = this;

me.control({
'product-configurator-settings-window product-options-tree': {
addProductOption: me.onAddProductOption
}
});
},

createMainWindow: function() {
var me = this,
window = me.getView('Window').create({
treeStore: Ext.create('Shopware.apps.CCBConfigurablePhotoProductsManager.store.ProductOptionsList').load()
}).show();

return window;
},

onAddProductOption: function() {
var me = this,
optionsTree = me.getProductOptionsTree(),
parentNode = optionsTree.getRootNode(),
nodeCount = parentNode.childNodes.length + 1,
productOption = Ext.create('Shopware.apps.CCBConfigurablePhotoProductsManager.model.ProductOption', {
parent: 0,
type: 0,
title: Ext.String.format('{s name="group/default_name"}New Group [0]{/s}', optionsTree.getRootNode().childNodes.length + 1),
active: true,
leaf: false
});
productOption.setDirty();
parentNode.appendChild(productOption);
optionsTree.getStore().sync(); // Nothing arrives at DB
optionsTree.expandAll();
},

// ...

вид / window.js

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager.view.Window', {

extend:'Enlight.app.Window',

cls:Ext.baseCSSPrefix + 'product-configurator-settings-window',
alias:'widget.product-configurator-settings-window',

border:false,
autoShow:true,
maximizable:true,
minimizable:true,

layout: {
type: 'hbox',
align: 'stretch'
},

width: 700,
height: 400,

initComponent:function () {
var me = this;
me.createItems();
me.title = '{s name=window/title}Configurator Settings{/s}';
me.callParent(arguments);
},

createItems: function() {
var me = this;

me.items = [
me.createProductOptionsTree()
];
},

createProductOptionsTree: function() {
var me = this;
return Ext.create('Shopware.apps.CCBConfigurablePhotoProductsManager.view.ProductOptions', {
store: me.treeStore,
width: '20%',
flex: 1
});
}
});

магазин / product_options_list.js

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager.store.ProductOptionsList', {
extend: 'Ext.data.TreeStore',
pageSize: 30,
autoLoad: false,
remoteSort: true,
remoteFilter: true,
model : 'Shopware.apps.CCBConfigurablePhotoProductsManager.model.ProductOption',
proxy:{
type:'ajax',
url:'{url controller="CCBConfigurablePhotoProductsManager" action="getProductOptionsList"}',
reader:{
type:'json',
root:'data',
totalProperty:'total'
}
}
});

модель / product_option.js

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager.model.ProductOption', {
extend : 'Ext.data.Model',
fields : [
{ name : 'id', type : 'int', useNull: true },
{ name : 'parent', type : 'int' },
{ name : 'title', type : 'string' },
{ name : 'active', type: 'boolean' },
{ name : 'type', type : 'int' }
],
idProperty : 'id',
proxy : {
type : 'ajax',
api: {
create: '{url controller="CCBConfigurablePhotoProductsManager" action="createProductOption"}',
update: '{url controller="CCBConfigurablePhotoProductsManager" action="updateProductOption"}',
destroy: '{url controller="CCBConfigurablePhotoProductsManager" action="deleteProductOption"}'
},
reader : {
type : 'json',
root : 'data',
totalProperty: 'total'
}
}
});

PHP / controller.php

<?php
use Shopware\CustomModels\CCB\ProductOption;

class Shopware_Controllers_Backend_CCBConfigurablePhotoProductsManager extends Shopware_Controllers_Backend_ExtJs
{

public function createProductOptionAction()
{
// Never being called
file_put_contents('~/test.log', "createProductOptionAction\n", FILE_APPEND);
$this->View()->assign(
$this->saveProductOption($this->Request()->getParams())
);
}

public function getProductOptionsListAction()
{
// Works fine
file_put_contents('~/test.log', "getProductOptionsListAction\n", FILE_APPEND);
// ...
}

// ...

РЕДАКТИРОВАТЬ 1

Я попытался добавить писателя для магазина и модели, как это было предложено Саки. Но, к сожалению, это все еще не работает. createProductOptionAction() в контроллере PHP никогда не вызывается.

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager.model.ProductOption', {
extend : 'Ext.data.Model',
fields : [
{ name : 'id', type : 'int', useNull: true },
{ name : 'parent', type : 'int' },
{ name : 'title', type : 'string' },
{ name : 'active', type: 'boolean' },
{ name : 'type', type : 'int' }
],
idProperty : 'id',
proxy : {
type: 'ajax',
api: {
create: '{url controller="CCBConfigurablePhotoProductsManager" action="createProductOption"}',
update: '{url controller="CCBConfigurablePhotoProductsManager" action="updateProductOption"}',
destroy: '{url controller="CCBConfigurablePhotoProductsManager" action="deleteProductOption"}'
},
reader: {
type : 'json',
root : 'data',
totalProperty: 'total'
},
writer: {
type: 'json'
}
}
});

Что мне интересно, оригинальный плагин не был реализован писателем. Но при добавлении записи она сразу появилась в базе данных.

РЕДАКТИРОВАТЬ 2

Я добавил несколько слушателей store.ProductOptionsList:

Ext.define('Shopware.apps.CCBConfigurablePhotoProductsManager.store.ProductOptionsList', {
extend: 'Ext.data.TreeStore',
pageSize: 30,
autoLoad: false,
remoteSort: true,
remoteFilter: true,
model : 'Shopware.apps.CCBConfigurablePhotoProductsManager.model.ProductOption',
root: {
text: 'Product Options',
id: 'productOptions',
expanded: true
},
proxy:{
type: 'ajax',
url: '{url controller="CCBConfigurablePhotoProductsManager" action="getProductOptionsList"}',
reader: {
type:'json',
root:'data',
totalProperty:'total'
}
},
listeners: {
add: function(store, records, index, eOpts) {
console.log("**** Add fired");
console.log(records);
},
append: function(store, node, index, eOpts) {
console.log("**** Append fired");
console.log(node);
},
beforesync: function(operations) {
console.log("**** Beforesync fired");
console.log(operations);
}
}
});

Все эти события становятся уволенными. beforesync показывает события

**** Beforesync fired
Object {create: Array[1]}
create: Array[1]
...

Но все же запросы API model.ProductOption не увольняют. Он должен работать. Не должно ли это? Может быть, это ошибка в ExtJS 4.1? Или что-то с Shopware + ExtJS?

РЕДАКТИРОВАТЬ 3

Хорошо, это действительно странно.

Я добавил «write» -Listener к TreeStore,

    write: function(store, operation, opts){
console.log("**** Write fired");
console.log(operation);
Ext.each(operation.records, function(record){
console.log("**** ...");
if (record.dirty) {
console.log("**** Commiting dirty record");
record.commit();
}
});
}

После добавления узла и вызова .getStore().sync(), write— событие уволено, он повторяется operation.records, находит одну запись (ту, которую я только что добавил) … но это не так dirtyхотя я делаю productOption.setDirty() прежде чем добавить его в дерево ?!

Большое спасибо за ваше время! 🙂

0

Решение

Небольшая заметка о вашем коде:
Ошибка в beforesync событие: функция должна вернуть trueиначе sync() не будет уволен.

Я не думаю, что это единственная проблема. Поскольку ExtJs — это обычно обширный код, я не могу сказать вам, в чем причина вашей проблемы. Все, что я могу дать, это простой рабочий пример с некоторыми пояснениями.

Я следую рекомендованному макету MVC, то есть одному файлу для каждого класса. Вот полный код:

Ext.define('Sandbox.Application', {
name: 'Sandbox',
extend: 'Ext.app.Application',
controllers: [
'Sandbox.controller.Trees'
]
});
Ext.define('Sandbox.controller.Trees', {
extend: 'Ext.app.Controller',
requires: ['Ext.tree.*', 'Ext.data.*', 'Ext.grid.*'],
models: ['TreeTest'],
stores: ['TreeTest'],
views: ['TreeGrid'],
init: function(){
this.control({
'treegrid toolbar button#addchild': {click: this.onAddChild},
'treegrid toolbar button#removenode': {click: this.onRemoveNode}
})
},
onAddChild: function(el){
var grid = el.up('treepanel'),
sel = grid.getSelectionModel().getSelection()[0],
store = grid.getStore();
store.suspendAutoSync()
var child = sel.appendChild({task: '', user: '', leaf: true});
sel.set('leaf', false)
sel.expand()
grid.getView().editingPlugin.startEdit(child);
store.resumeAutoSync();
},
onRemoveNode: function(el){
var grid = el.up('treepanel'),
sel = grid.getSelectionModel().getSelection()[0];
sel.remove()
}
});
Ext.define('Sandbox.model.TreeTest', {
extend: 'Ext.data.TreeModel',
fields: [
{name: 'id',  type: 'int'},
{name: 'task',  type: 'string'},
{name: 'user', type: 'string'},
{name: 'index', type: 'int'},
{name: 'parentId', type: 'int'},
{name: 'leaf', type: 'boolean', persist: false}
]
});
Ext.define('Sandbox.store.TreeTest', {
extend: 'Ext.data.TreeStore',
model: 'Sandbox.model.TreeTest',
proxy: {
type: 'ajax',
url: 'resources/treedata.php',
api: {
create: 'resources/treedata.php?action=create',
read: undefined,
update: 'resources/treedata.php?action=update',
destroy: 'resources/treedata.php?action=destroy'
}
},
autoSync: true,
autoLoad: false,
root: {id: 1, text: "Root Node", expanded: false}
});
Ext.define('Sandbox.view.TreeGrid', {
extend: 'Ext.tree.Panel',
alias: 'widget.treegrid',
store: 'TreeTest',
columns: [{
xtype: 'treecolumn',
text: 'Task',
flex: 2,
sortable: true,
dataIndex: 'task',
editor: {xtype: 'textfield', allowBlank: false}
},{
dataIndex: 'id',
align: 'right',
text: 'Id'
}, {
dataIndex: 'user',
flex: 1,
text: 'Utilisateur',
editor: {xtype: 'textfield', allowBlank: false}
}],
plugins: [{
ptype: 'rowediting',
clicksToMoveEditor: 1,
autoCancel: false
}],
viewConfig: {
plugins: [{
ptype: 'treeviewdragdrop',
containerScroll: true
}]
},
tbar:[
{xtype: 'button', text: 'Add Child', itemId: 'addchild'},
{xtype: 'button', text: 'Remove', itemId: 'removenode'}
]
});

Я не разработал серверный код. Я просто скопировал Пример кода кухонной раковины. Чтобы заставить работать запрос на создание, обновление или удаление, он должен вернуть измененные строки вместе с success: true,

Пояснения:

  • Мне нужно было запустить sencha app build после добавления необходимых классов, чтобы все отображалось правильно
  • файл model/TreeTest.js : поле index требуется, если мы хотим, чтобы повторный заказ был сохранен на сервере. Если он пропущен, только строки с отредактированными полями сохраняются обратно. Надо было добавить persist: false для leaf поле, потому что эти данные не нужны на сервере.
  • файл store/TreeTest.js :

    • autoSync: true работал из коробки, с ограничением, упомянутым при переупорядочении.
    • дерево автоматически загружается, когда корневой узел expanded: true или если autoLoad: true, Если мы не хотим автозагрузку, autoLoad а также expanded должны быть оба ложными.
    • Корень требуется для хорошего рабочего магазина. Если он отсутствует, мы должны загрузить магазин вручную, даже если autoLoad: true,
    • Надо было добавить api конфигурации. Без этого невозможно было сообщить appart обновление, создать и удалить запрос.
  • файл view/TreeGrid.js :

    • столбец с xtype: 'treecolumn' необходимо.
    • Удаление строки просто и синхронизирует хранилище автоматически. Серверная сторона отвечает за удаление дочерних элементов, если они есть.
    • Создание новой строки сложнее, потому что магазин sync()как только appendChild() называется (suspendAutoSync() используется, чтобы избежать написания нового потомка до его редактирования). Кроме того, сетка обновляется только, если мы контролируем leaf свойство вручную (.set('leaf', false)). Я ожидаю, что ExtJs правильно управлять leaf свойство и считают это ошибкой.
1

Другие решения

Используемый магазином прокси должен иметь писатель настроен для синхронизации операций для общения с сервером.

0

По вопросам рекламы [email protected]