Skip to content

Commit

Permalink
[Feature]: Manage select options via interface
Browse files Browse the repository at this point in the history
Add Select Options management interface via Settings > Data Objects submenu.
Add selectoptions permission to allow access to management interface.
Add options source selection to select fields definition to switch between
direct configuration, select options or class / service configuration.
Generate configuration file and enum to store select options.
Introduce OptionsProviderInterface to detect field definitions using provider.
Introduce OptionsProviderTrait to share properties between select types.
Update classes rebuild command to also rebuild select options.
Add PHP and JavaScript reserved words helper classes.
Add and update documentation.
Relates to pimcore#3409
  • Loading branch information
kjkooistra-youwe committed Mar 10, 2023
1 parent aaded2c commit 7448186
Show file tree
Hide file tree
Showing 61 changed files with 2,855 additions and 128 deletions.
4 changes: 4 additions & 0 deletions bundles/AdminBundle/public/css/icons.css
Expand Up @@ -335,6 +335,10 @@
background: url(/bundles/pimcoreadmin/img/flat-white-icons/bricks.svg) center center no-repeat !important;
}

.pimcore_nav_icon_selectoptions {
background: url(/bundles/pimcoreadmin/img/flat-white-icons/expand.svg) center center no-repeat !important;
}

.pimcore_nav_icon_quantityValue {
background: url(/bundles/pimcoreadmin/img/flat-white-icons/calculator.svg) center center no-repeat !important;
}
Expand Down
19 changes: 18 additions & 1 deletion bundles/AdminBundle/public/js/pimcore/layout/toolbar.js
Expand Up @@ -594,6 +594,15 @@ pimcore.layout.toolbar = Class.create({
});
}

if (perspectiveCfg.inToolbar('settings.objects.selectoptions') && user.isAllowed('selectoptions')) {
objectMenu.menu.items.push({
text: t('selectoptions'),
iconCls: 'pimcore_nav_icon_selectoptions',
itemId: 'pimcore_menu_settings_data_objects_selectoptions',
handler: this.editSelectOptions
});
}

if (perspectiveCfg.inToolbar("settings.objects.quantityValue") && user.isAllowed("quantityValueUnits")) {
objectMenu.menu.items.push({
text: t("quantityValue_field"),
Expand Down Expand Up @@ -787,7 +796,7 @@ pimcore.layout.toolbar = Class.create({
}
});
}

// help menu
menu.settings = {
label: t('settings'),
Expand Down Expand Up @@ -1176,6 +1185,14 @@ pimcore.layout.toolbar = Class.create({
}
},

editSelectOptions: function () {
try {
pimcore.globalmanager.get('selectoptions').activate();
} catch (e) {
pimcore.globalmanager.add('selectoptions', new pimcore.object.selectoptions());
}
},

clearCache: function (params) {
Ext.Msg.confirm(t('warning'), t('system_performance_stability_warning'), function(btn){
if (btn == 'yes'){
Expand Down
Expand Up @@ -277,24 +277,14 @@ pimcore.object.classes.data.multiselect = Class.create(pimcore.object.classes.da
triggerAction: "all",
editable: false,
forceSelection: true
},
{
xtype: "textfield",
fieldLabel: t("options_provider_class"),
width: 600,
name: "optionsProviderClass",
value: datax.optionsProviderClass
},
{
xtype: "textfield",
fieldLabel: t("options_provider_data"),
width: 600,
value: datax.optionsProviderData,
name: "optionsProviderData"
},
valueGrid
}
];

specificItems = specificItems.concat(
pimcore.object.helpers.selectField.getOptionsProviderFields(datax, valueGrid)
);
specificItems.push(valueGrid);

return specificItems;
},

Expand Down Expand Up @@ -331,6 +321,7 @@ pimcore.object.classes.data.multiselect = Class.create(pimcore.object.classes.da
height: source.datax.height,
maxItems: source.datax.maxItems,
renderType: source.datax.renderType,
optionsProviderType: source.datax.optionsProviderType,
optionsProviderClass: source.datax.optionsProviderClass,
optionsProviderData: source.datax.optionsProviderData
});
Expand Down
Expand Up @@ -271,21 +271,9 @@ pimcore.object.classes.data.select = Class.create(pimcore.object.classes.data.da
value: datax.defaultValueGenerator
});

items.push({
xtype: "textfield",
fieldLabel: t("options_provider_class"),
width: 600,
name: "optionsProviderClass",
value: datax.optionsProviderClass
});

items.push({
xtype: "textfield",
fieldLabel: t("options_provider_data"),
width: 600,
value: datax.optionsProviderData,
name: "optionsProviderData"
});
items = items.concat(
pimcore.object.helpers.selectField.getOptionsProviderFields(datax, valueGrid)
)

items.push(valueGrid);
return items;
Expand Down Expand Up @@ -318,6 +306,7 @@ pimcore.object.classes.data.select = Class.create(pimcore.object.classes.data.da
{
options: source.datax.options,
width: source.datax.width,
optionsProviderType: source.datax.optionsProviderType,
optionsProviderClass: source.datax.optionsProviderClass,
optionsProviderData: source.datax.optionsProviderData,
defaultValue: source.datax.defaultValue,
Expand Down
6 changes: 5 additions & 1 deletion bundles/AdminBundle/public/js/pimcore/object/helpers/grid.js
Expand Up @@ -84,7 +84,11 @@ pimcore.object.helpers.grid = Class.create({
var key = fieldConfig.key;
var readerFieldConfig = {name: key};
// dynamic select returns data + options on cell level
if ((type == "select" || type == "multiselect") && fieldConfig.layout.optionsProviderClass) {
if (
(type == "select" || type == "multiselect")
&& fieldConfig.layout.optionsProviderType !== pimcore.object.helpers.selectField.OPTIONS_PROVIDER_TYPE_CLASS
&& fieldConfig.layout.optionsProviderClass
) {
if (typeof noBatchColumns != "undefined") {
if (fieldConfig.layout.dynamicOptions) {
noBatchColumns.push(key);
Expand Down
@@ -0,0 +1,55 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

pimcore.registerNS('pimcore.object.helpers.reservedWords');

pimcore.object.helpers.reservedWords = {
// https://www.php.net/manual/en/reserved.keywords.php
phpReservedKeywords: [
'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue',
'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach',
'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'finally', 'fn', 'for', 'foreach',
'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof',
'interface', 'isset', 'list', 'match', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public',
'readonly', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use',
'var', 'while', 'xor', 'yield', 'yield_from'
],

// https://www.php.net/manual/en/reserved.classes.php
phpReservedClasses: [
'self', 'static', 'parent'
],

// https://www.php.net/manual/en/reserved.other-reserved-words.php
phpOtherReservedWords: [
'int', 'float', 'bool', 'string', 'true', 'false', 'null', 'void', 'iterable', 'object', 'mixed', 'never',
'enum', 'resource', 'numeric'
],

pimcore: [
// Pimcore
'data', 'folder', 'permissions', 'dao', 'concrete', 'items'
],

isReservedWord: function (word) {
return in_arrayi(word, this.getAllReservedWords());
},

getAllReservedWords: function () {
return this.phpReservedKeywords.concat(
this.phpReservedClasses,
this.phpOtherReservedWords,
this.pimcore
);
}
};
163 changes: 163 additions & 0 deletions bundles/AdminBundle/public/js/pimcore/object/helpers/selectField.js
@@ -0,0 +1,163 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

pimcore.registerNS('pimcore.object.helpers.selectField');

/**
* @private
*/
pimcore.object.helpers.selectField = {
OPTIONS_PROVIDER_TYPE_CONFIGURE: 'configure',
OPTIONS_PROVIDER_TYPE_SELECT_OPTIONS: 'select_options',
OPTIONS_PROVIDER_TYPE_CLASS: 'class',

selectOptionsStore: null,

/**
* @param {Object} datax
* @param {Ext.grid.Panel} valueGrid
* @returns {[
* Ext.form.field.ComboBox,
* Ext.form.field.Text,
* Ext.form.field.Text,
* Ext.form.field.ComboBox
* ]}
*/
getOptionsProviderFields: function (datax, valueGrid) {
var selectOptionsSelector = Ext.create('Ext.form.field.ComboBox', {
fieldLabel: t('selectoptions'),
emptyText: '',
value: datax.optionsProviderData,
hidden: true,
valueField: 'id',
displayField: 'text',
editable: false,
forceSelection: true,
queryMode: 'local',
store: this.getSelectOptionsStore(),
listeners: {
change: function (comboBox, newValue) {
optionsProviderClass.setValue('\\Pimcore\\Bundle\\AdminBundle\\OptionsProvider\\SelectOptionsOptionsProvider');
optionsProviderData.setValue(newValue);
}
}
});

var optionsProviderClass = Ext.create('Ext.form.field.Text', {
fieldLabel: t('options_provider_class'),
width: 600,
name: 'optionsProviderClass',
hidden: true,
value: datax.optionsProviderClass
});

var optionsProviderData = Ext.create('Ext.form.field.Text', {
fieldLabel: t('options_provider_data'),
width: 600,
value: datax.optionsProviderData,
hidden: true,
name: 'optionsProviderData'
});

var toggleFields = function (optionsProviderType) {
switch (optionsProviderType) {
case this.OPTIONS_PROVIDER_TYPE_SELECT_OPTIONS:
optionsProviderClass.hide();
optionsProviderData.hide();
selectOptionsSelector.show();
valueGrid.hide();
break;
case this.OPTIONS_PROVIDER_TYPE_CLASS:
optionsProviderClass.show();
optionsProviderData.show();
selectOptionsSelector.hide();
valueGrid.hide();
break;
// Configure
default:
optionsProviderClass.hide();
optionsProviderData.hide();
selectOptionsSelector.hide();
valueGrid.show();
}
}.bind(this)

var typeValue = this.OPTIONS_PROVIDER_TYPE_CONFIGURE;
if (datax.optionsProviderType) {
typeValue = datax.optionsProviderType;
// Legacy fallback in case no type is set and a class/service is configured
} else if (datax.optionsProviderClass) {
typeValue = this.OPTIONS_PROVIDER_TYPE_CLASS;
}

toggleFields(typeValue);

var optionsProviderType = Ext.create('Ext.form.field.ComboBox', {
name: 'optionsProviderType',
fieldLabel: t('options_provider_type'),
value: typeValue,
valueField: 'value',
displayField: 'label',
editable: false,
forceSelection: true,
queryMode: 'local',
store: Ext.create('Ext.data.Store', {
fields: ['value', 'label'],
data: [
{value: this.OPTIONS_PROVIDER_TYPE_CONFIGURE, label: t('options_provider_type_configure')},
{value: this.OPTIONS_PROVIDER_TYPE_SELECT_OPTIONS, label: t('options_provider_type_select_options')},
{value: this.OPTIONS_PROVIDER_TYPE_CLASS, label: t('options_provider_type_class')}
]
}),
listeners: {
change: function (comboBox, newValue) {
toggleFields(newValue);
}
}
});

return [
optionsProviderType,
optionsProviderClass,
optionsProviderData,
selectOptionsSelector
];
},

/**
* @returns {Ext.data.JsonStore}
*/
getSelectOptionsStore: function () {
if (this.selectOptionsStore === null) {
this.selectOptionsStore = Ext.create('Ext.data.JsonStore', {
fields: [
{name: 'id'},
{name: 'text'}
],
autoLoad: true,
proxy: {
type: 'ajax',
url: Routing.generate('pimcore_admin_dataobject_class_selectoptionstree'),
reader: {
type: 'json'
},
extraParams: {
grouped: 0
}
},
});
}

return this.selectOptionsStore;
}
};

0 comments on commit 7448186

Please sign in to comment.