diff --git a/src/DataDefinitionsBundle/DependencyInjection/DataDefinitionsExtension.php b/src/DataDefinitionsBundle/DependencyInjection/DataDefinitionsExtension.php index ec135838..e2563e09 100644 --- a/src/DataDefinitionsBundle/DependencyInjection/DataDefinitionsExtension.php +++ b/src/DataDefinitionsBundle/DependencyInjection/DataDefinitionsExtension.php @@ -76,6 +76,7 @@ public function load(array $configs, ContainerBuilder $container) $config['pimcore_admin']['js']['process_manager_import'] = '/bundles/datadefinitions/pimcore/js/process_manager/import_definitions.js'; $config['pimcore_admin']['js']['process_manager_export'] = '/bundles/datadefinitions/pimcore/js/process_manager/export_definitions.js'; $config['pimcore_admin']['js']['process_manager_export_contextmenu'] = '/bundles/datadefinitions/pimcore/js/process_manager/export_contextmenu.js'; + $config['pimcore_admin']['js']['process_manager_export_search'] = '/bundles/datadefinitions/pimcore/js/process_manager/export_search.js'; $loader->load('process_manager.yml'); } diff --git a/src/DataDefinitionsBundle/Fetcher/ObjectsFetcher.php b/src/DataDefinitionsBundle/Fetcher/ObjectsFetcher.php index 6aaefbcb..d4effa0a 100644 --- a/src/DataDefinitionsBundle/Fetcher/ObjectsFetcher.php +++ b/src/DataDefinitionsBundle/Fetcher/ObjectsFetcher.php @@ -49,8 +49,6 @@ private function getClassListing(ExportDefinitionInterface $definition, $params) { $class = $definition->getClass(); $classDefinition = ClassDefinition::getByName($class); - $obj = null; - if (!$classDefinition instanceof ClassDefinition) { throw new \InvalidArgumentException(sprintf('Class not found %s', $class)); } @@ -59,16 +57,72 @@ private function getClassListing(ExportDefinitionInterface $definition, $params) $list = new $classList; $list->setUnpublished($definition->isFetchUnpublished()); + $rootNode = null; + $conditionFilters = []; if (isset($params['root'])) { $rootNode = Concrete::getById($params['root']); if (null !== $rootNode) { - $list->addConditionParam('o_path LIKE :path', ['path' => $rootNode->getFullPath().'%']); + $quotedPath = $list->quote($rootNode->getRealFullPath()); + $quotedWildcardPath = $list->quote(str_replace('//', '/', $rootNode->getRealFullPath() . '/') . '%'); + $conditionFilters[] = '(o_path = ' . $quotedPath . ' OR o_path LIKE ' . $quotedWildcardPath . ')'; + } + } + + if ($params['query']) { + $query = $this->filterQueryParam($params['query']); + if (!empty($query)) { + $conditionFilters[] = 'oo_id IN (SELECT id FROM search_backend_data WHERE MATCH (`data`,`properties`) AGAINST (' . $list->quote($query) . ' IN BOOLEAN MODE))'; + } + } + + if ($params['only_direct_children'] == 'true' && null !== $rootNode) { + $conditionFilters[] = 'o_parentId = ' . $rootNode->getId(); + } + + if ($params['condition']) { + $conditionFilters[] = '(' . $params['condition'] . ')'; + } + if ($params['ids']) { + $quotedIds = []; + foreach ($params['ids'] as $id) { + $quotedIds[] = $list->quote($id); + } + if (!empty($quotedIds)) { + $conditionFilters[] = 'oo_id IN (' . implode(',', $quotedIds) . ')'; } } + + $list->setCondition(implode(' AND ', $conditionFilters)); return $list; } + + /** + * @param string $query + * + * @return string + */ + protected function filterQueryParam(string $query) + { + if ($query == '*') { + $query = ''; + } + + $query = str_replace('%', '*', $query); + $query = str_replace('@', '#', $query); + $query = preg_replace("@([^ ])\-@", '$1 ', $query); + + $query = str_replace(['<', '>', '(', ')', '~'], ' ', $query); + + // it is not allowed to have * behind another * + $query = preg_replace('#[*]+#', '*', $query); + + // no boolean operators at the end of the query + $query = rtrim($query, '+- '); + + return $query; + } } class_alias(ObjectsFetcher::class, 'ImportDefinitionsBundle\Fetcher\ObjectsFetcher'); diff --git a/src/DataDefinitionsBundle/Form/Type/ProcessManager/ExportDefinitionObjectStartupForm.php b/src/DataDefinitionsBundle/Form/Type/ProcessManager/ExportDefinitionObjectStartupForm.php index b9ad2260..50b730a2 100644 --- a/src/DataDefinitionsBundle/Form/Type/ProcessManager/ExportDefinitionObjectStartupForm.php +++ b/src/DataDefinitionsBundle/Form/Type/ProcessManager/ExportDefinitionObjectStartupForm.php @@ -15,6 +15,8 @@ namespace Wvision\Bundle\DataDefinitionsBundle\Form\Type\ProcessManager; use ProcessManagerBundle\Form\Type\AbstractStartupFormType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -28,7 +30,22 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder ->add('root', TextType::class, [ 'required' => false - ]); + ]) + ->add('query', TextType::class, [ + 'required' => false + ]) + ->add('only_direct_children', CheckboxType::class, [ + 'required' => false + ]) + ->add('condition', TextType::class, [ + 'required' => false + ]) + ->add('ids', CollectionType::class, [ + 'allow_add' => true, + 'entry_type' => TextType::class, + 'required' => false + ]) + ; } } diff --git a/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_contextmenu.js b/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_contextmenu.js index 0dd74949..28383438 100644 --- a/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_contextmenu.js +++ b/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_contextmenu.js @@ -33,15 +33,16 @@ pimcore.plugin.datadefinitions.export.context_menu = Class.create(pimcore.plugin rootProperty: 'data' } }, + sorters: [{ + property: 'name', + direction: 'ASC' + }], + sortRoot: 'data', autoLoad: true, listeners: { - load: function(store, executables, successful) { - if (!successful) { - return; - } - + refresh: function(store) { var exportMenu = []; - executables.forEach(function (executable) { + store.each(function (executable) { exportMenu.push({ text: executable.get('name'), iconCls: "pimcore_icon_object pimcore_icon_overlay_add", @@ -53,7 +54,7 @@ pimcore.plugin.datadefinitions.export.context_menu = Class.create(pimcore.plugin tree.add([ { xtype: 'menuseparator' }, { - text: t("importdefinitions_processmanager_export_from_here"), + text: t("data_definitions_processmanager_export_from_here"), iconCls: "pimcore_icon_object pimcore_icon_overlay_download", menu: exportMenu } diff --git a/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_search.js b/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_search.js new file mode 100644 index 00000000..238dbecb --- /dev/null +++ b/src/DataDefinitionsBundle/Resources/public/pimcore/js/process_manager/export_search.js @@ -0,0 +1,110 @@ +/** + * Data Definitions. + * + * LICENSE + * + * This source file is subject to the GNU General Public License version 3 (GPLv3) + * For the full copyright and license information, please view the LICENSE.md and gpl-3.0.txt + * files that are distributed with this source code. + * + * @copyright Copyright (c) 2016-2019 w-vision AG (https://www.w-vision.ch) + * @license https://github.com/w-vision/ImportDefinitions/blob/master/gpl-3.0.txt GNU General Public License version 3 (GPLv3) + */ + +pimcore.object.search = Class.create(pimcore.object.search, { + createGrid: function ($super, fromConfig, response, settings, save) { + if (!Ext.ClassManager.get('Executable')) { + Ext.define('Executable', { + extend: 'Ext.data.Model', + fields: [ + {name: 'name', type: 'string'}, + ] + }); + } + + this.exportFromHere = new Ext.SplitButton({ + text: t('data_definitions_processmanager_export_from_here'), + iconCls: "pimcore_icon_object pimcore_icon_overlay_add", + menu: [] + }); + + var $this = this; + Ext.create('Ext.data.Store', { + model: 'Executable', + proxy: { + type: 'ajax', + url: '/admin/process_manager/executables/list-by-type', + extraParams: { + type: 'exportdefinition' + }, + reader: { + type: 'json', + rootProperty: 'data' + } + }, + sorters: [{ + property: 'name', + direction: 'ASC' + }], + sortRoot: 'data', + autoLoad: true, + listeners: { + refresh: function(store) { + var exportMenu = []; + store.each(function (executable) { + exportMenu.push({ + text: executable.get('name'), + iconCls: "pimcore_icon_object pimcore_icon_overlay_add", + handler: $this.exportObjects.bind($this, executable) + }); + }); + + if (exportMenu) { + $this.exportFromHere.down("menu").add(exportMenu); + } + } + } + }); + + $super(fromConfig, response, settings, save); + this.grid.down("toolbar").add([ + "-", + this.exportFromHere, + "-" + ]); + }, + + exportObjects: function (executable, menuItem) { + var selected = this.grid.getSelectionModel().getSelection(), ids = []; + if (selected) { + ids = selected.map(function (item) { + return item.id; + }); + } + + Ext.Ajax.request({ + url: '/admin/process_manager/executables/run', + params: { + id: executable.id, + startupConfig: Ext.encode({ + root: this.object.id, + query: this.searchField.getValue(), + only_direct_children: this.checkboxOnlyDirectChildren.getValue(), + condition: this.sqlEditor.getValue(), + ids: ids, + }), + csrfToken: pimcore.settings['csrfToken'] + }, + method: 'POST', + success: function (result) { + result = Ext.decode(result.responseText); + + if (result.success) { + Ext.Msg.alert(t('success'), t('processmanager_executable_started')); + } else { + Ext.Msg.alert(t('error'), result.message); + } + }.bind(this) + }); + } +});