commit 17bcd332daab889b5af89e8b938d1413bbed5052
parent 06595d45564fa4f8973a6095a65142be8bb3e3da
Author: Felicia Hummel <felicia@partkeepr.com>
Date: Tue, 27 Dec 2016 17:28:48 +0100
Initial commit of m:n relation export
Diffstat:
8 files changed, 138 insertions(+), 56 deletions(-)
diff --git a/src/PartKeepr/ExportBundle/EventListener/AbstractResponderViewListener.php b/src/PartKeepr/ExportBundle/EventListener/AbstractResponderViewListener.php
@@ -102,7 +102,12 @@ abstract class AbstractResponderViewListener
$finalData[$key][$mapping] = $finalData[$key][$mapping]->format(\DateTime::W3C);
}
}
+
+ if ($finalData[$key][$mapping] === null) {
+ $finalData[$key][$mapping] = "null";
+ }
} catch (\Exception $e) {
+ $finalData[$key][$mapping] = "null";
}
}
}
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/ModelTreeMaker/ModelTreeMaker.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/ModelTreeMaker/ModelTreeMaker.js
@@ -59,14 +59,16 @@ Ext.define("PartKeepr.ModelTreeMaker.ModelTreeMaker", {
if (fields[i]["$reference"] === undefined) {
// Field is a scalar field
if (this.ignoreFields.indexOf(fields[i].name) === -1 && !this.customFieldIgnorer(fields[i])) {
- newNode = node.appendChild({
+
+ newNode = node.appendChild(Ext.create("PartKeepr.Data.ReflectionFieldTreeModel", {
text: fields[i].name,
leaf: true,
data: {
name: prefix + fields[i].name,
type: "field"
- }
- });
+ },
+ entityIndex: ""
+ }));
if (callback) {
newNode.set(callback(fields[i], newNode));
@@ -83,14 +85,14 @@ Ext.define("PartKeepr.ModelTreeMaker.ModelTreeMaker", {
}
if (!associationAlreadyProcessed) {
- childNode = node.appendChild({
+ childNode = node.appendChild(Ext.create("PartKeepr.Data.ReflectionFieldTreeModel", {
text: fields[i].name,
data: {
name: prefix + fields[i].name,
type: "manytoone"
},
leaf: false
- });
+ }));
if (callback) {
childNode.set(callback(fields[i], childNode));
@@ -114,7 +116,7 @@ Ext.define("PartKeepr.ModelTreeMaker.ModelTreeMaker", {
}
if (!associationAlreadyProcessed) {
- childNode = node.appendChild({
+ childNode = node.appendChild(Ext.create("PartKeepr.Data.ReflectionFieldTreeModel",{
text: associations[i].name,
data: {
name: prefix + associations[i].name,
@@ -122,7 +124,7 @@ Ext.define("PartKeepr.ModelTreeMaker.ModelTreeMaker", {
reference: associations[i].cls
},
leaf: false
- });
+ }));
if (callback) {
childNode.set(callback(associations[i].cls, childNode));
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Project/ProjectPartGrid.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Project/ProjectPartGrid.js
@@ -93,7 +93,7 @@ Ext.define('PartKeepr.ProjectPartGrid', {
this.bbar = [
Ext.create("PartKeepr.Exporter.GridExporterButton", {
itemId: 'export',
- genericExporter: false,
+ genericExporter: true,
tooltip: i18n("Export"),
iconCls: "fugue-icon application-export",
disabled: this.store.isLoading()
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/EntityQueryPanel.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/EntityQueryPanel.js
@@ -13,7 +13,15 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
region: 'east',
width: 265,
itemId: 'fieldTree',
+ plugins: {
+ ptype: 'cellediting',
+ clicksToEdit: 1,
+ pluginId: "cellediting",
+ },
split: true,
+ viewConfig: {
+ markDirty: false
+ },
store: {
folderSort: true,
sorters: [
@@ -23,6 +31,33 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
}
]
},
+ columns: [
+ {
+ xtype: 'treecolumn', //this is so we know which column will show the tree
+ text: i18n("Field"),
+ dataIndex: 'text',
+ flex: 3,
+ }, {
+ text: i18n("Index"),
+ flex: 1,
+ align: 'center',
+ dataIndex: 'entityIndex',
+ format: '0',
+ editor: {
+ xtype: 'numberfield',
+ minValue: 0,
+ maxValue: 99
+ },
+ renderer: function (val, md, record) {
+ if (record.get("data") !== null &&
+ record.get("data").type !== "onetomany") {
+ return "";
+ } else {
+ return record.get("entityIndex");
+ }
+ }
+ }
+ ],
useArrows: true
}
],
@@ -50,7 +85,11 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
this.down("#fieldTree").on("itemdblclick", this.onTreeDblClick, this);
rootNode.set("text", this.model.getName());
- this.treeMaker(rootNode, this.model, "");
+ var treeMaker = Ext.create("PartKeepr.ModelTreeMaker.ModelTreeMaker");
+ treeMaker.addIgnoreField("@id");
+ treeMaker.make(rootNode, this.model, "", Ext.bind(this.appendFieldData, this), ["entityIndex"]);
+ rootNode.expand();
+
rootNode.expand();
this.store = Ext.create("Ext.data.Store", {
@@ -75,10 +114,27 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
}
]
});
+
+ this.down("#fieldTree").getPlugin("cellediting").on("beforeedit", this.onBeforeEdit, this);
this.down("#grid").addDocked(this.bottomToolbar);
this.down("#grid").reconfigure(this.store, this.columns);
},
+ onBeforeEdit: function (editor, context)
+ {
+ if (context.record.get("data") !== null &&
+ context.record.get("data").type !== "onetomany") {
+
+ return false;
+ }
+ },
+ /**
+ * @param {Ext.data.field.Field} The model
+ */
+ appendFieldData: function (field, node)
+ {
+ node.set("entityIndex", 0);
+ },
/**
* Returns the parameters for the query string.
* @return {Object} An object containing all parameters
@@ -130,8 +186,15 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
*/
addColumn: function (record)
{
- var columns;
- if (this.hasColumn(record) || record.get("data") === undefined) {
+ var columns, fieldPath;
+
+ fieldPath = this.getFieldPath(record).join(".");
+
+ if (this.hasColumn(fieldPath) || record.get("data").name === undefined) {
+ return;
+ }
+
+ if (record.get("data").type !== "field") {
return;
}
@@ -140,8 +203,8 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
this.syncColumns();
this.columns.push({
- dataIndex: record.get("data"),
- text: record.get("data"),
+ dataIndex: fieldPath,
+ text: fieldPath,
renderer: function (value, metadata, record, rowIndex, colIndex)
{
return record.get(this.getColumns()[colIndex].dataIndex);
@@ -151,6 +214,22 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
this.down("#grid").reconfigure(this.store, this.columns);
},
+ getFieldPath: function (record)
+ {
+ var fieldPath = [];
+
+ if (record.parentNode !== null && !record.parentNode.isRoot()) {
+ fieldPath = this.getFieldPath(record.parentNode);
+ }
+
+ if (typeof(record.get("data")) === "object" && record.get("data").type === "onetomany") {
+ fieldPath.push(record.get("text") + "[" + record.get("entityIndex") + "]");
+ } else {
+ fieldPath.push(record.get("text"));
+ }
+
+ return fieldPath;
+ },
/**
* Removes a specific column to the grid. Must be a record and has the "data" property defined.
*
@@ -158,16 +237,18 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
*/
removeColumn: function (record)
{
- var i;
+ var i, fieldPath;
+
+ fieldPath = this.getFieldPath(record).join(".");
- if (!this.hasColumn(record) || record.get("data") === undefined) {
+ if (!this.hasColumn(fieldPath) || record.get("data").name === undefined) {
return;
}
this.syncColumns();
for (i = 0; i < this.columns.length; i++) {
- if (this.columns[i].dataIndex === record.get("data")) {
+ if (this.columns[i].dataIndex === fieldPath) {
Ext.Array.removeAt(this.columns, i);
}
}
@@ -205,12 +286,12 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
* @param {Ext.data.Model} The record to process
* @return {Boolean} true if the column exist, false otherwise
*/
- hasColumn: function (record)
+ hasColumn: function (name)
{
var i, columns = this.down('#grid').getColumns();
for (i = 0; i < columns.length; i++) {
- if (columns[i].dataIndex === record.get("data")) {
+ if (columns[i].dataIndex === name) {
return true;
}
}
@@ -225,45 +306,13 @@ Ext.define("PartKeepr.Widgets.EntityQueryPanel", {
*/
onTreeDblClick: function (tree, record)
{
- if (this.hasColumn(record)) {
+ var fieldPath = this.getFieldPath(record).join(".");
+
+ if (this.hasColumn(fieldPath)) {
this.removeColumn(record);
} else {
this.addColumn(record);
}
- },
- /**
- * Builds the field tree recursively. Handles infinite recursions (e.g. in trees).
- *
- * @param {Ext.data.NodeInterface} The current node
- * @param {Ext.data.Model} The model
- * @param {String} The prefix. Omit if first called
- */
- treeMaker: function (node, model, prefix)
- {
- var fields = model.getFields();
- this.visitedModels.push(model.getName());
- for (var i = 0; i < fields.length; i++) {
-
- if (fields[i]["$reference"] === undefined) {
- node.appendChild({
- text: fields[i].name,
- leaf: true,
- data: prefix + fields[i].name
- });
- } else {
- for (var j = 0; j < this.visitedModels.length; j++) {
- if (this.visitedModels[j] === fields[i].reference.cls.getName()) {
- return;
- }
- }
-
- var childNode = node.appendChild({
- text: fields[i].name,
- leaf: false
- });
-
- this.treeMaker(childNode, fields[i].reference.cls, prefix + fields[i].name + ".");
- }
- }
}
-});
+})
+;
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraModel.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraModel.js
@@ -15,7 +15,7 @@ Ext.define("PartKeepr.data.HydraModel", {
},
get: function (fieldName)
{
- var ret, role, item;
+ var ret, role, item, openingBracket, closingBracket, subEntity, index, subEntityStore;
ret = this.callParent(arguments);
@@ -35,6 +35,22 @@ Ext.define("PartKeepr.data.HydraModel", {
parts.shift();
return item.get(parts.join("."));
}
+ } else {
+ openingBracket = parts[0].indexOf("[");
+
+ if (openingBracket !== -1) {
+ subEntity = parts[0].substring(0, openingBracket);
+ closingBracket = parts[0].indexOf("]", openingBracket);
+ index = parts[0].substring(openingBracket+1, closingBracket);
+
+ subEntityStore = this[this.associations[subEntity].name]();
+ item = subEntityStore.getAt(index);
+
+ if (item !== null) {
+ parts.shift();
+ return item.get(parts.join("."));
+ }
+ }
}
}
return ret;
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Data/ReflectionFieldTreeModel.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Data/ReflectionFieldTreeModel.js
@@ -0,0 +1,8 @@
+Ext.define("PartKeepr.Data.ReflectionFieldTreeModel", {
+ extend: "Ext.data.TreeModel",
+
+ fields: [{
+ name: "entityIndex",
+ type: 'int'
+ }]
+});
diff --git a/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig b/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig
@@ -79,6 +79,7 @@
{% javascripts output='js/compiled/main2.js'
'@PartKeeprFrontendBundle/Resources/public/js/Util/i18n.js'
+ '@PartKeeprFrontendBundle/Resources/public/js/Data/ReflectionFieldTreeModel.js'
'@PartKeeprFrontendBundle/Resources/public/js/Components/Widgets/EntityQueryPanel.js'
'@PartKeeprFrontendBundle/Resources/public/js/Components/Widgets/EntityPicker.js'
'@PartKeeprFrontendBundle/Resources/public/js/Components/Widgets/PresetComboBox.js'
diff --git a/src/PartKeepr/ProjectBundle/Entity/ProjectPart.php b/src/PartKeepr/ProjectBundle/Entity/ProjectPart.php
@@ -45,6 +45,7 @@ class ProjectPart extends BaseEntity
* Specifies the project which belongs to this project part.
*
* @ORM\ManyToOne(targetEntity="PartKeepr\ProjectBundle\Entity\Project", inversedBy="parts")
+ * @Groups({"default"})
* @Assert\NotNull()
*
* @var Project