vendor/blackbit/data-director/EventListener/ClassChangedListener.php line 249

Open in your IDE?
  1. <?php
  2. /**
  3.  * Copyright Blackbit digital Commerce GmbH <info@blackbit.de>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
  6.  *
  7.  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  8.  *
  9.  * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  10.  */
  11. namespace Blackbit\DataDirectorBundle\EventListener;
  12. use Blackbit\DataDirectorBundle\lib\Pim\FieldType\CalculatedValueDataQuerySelector;
  13. use Blackbit\DataDirectorBundle\lib\Pim\Helper;
  14. use Blackbit\DataDirectorBundle\lib\Pim\Item\ItemMoldBuilder;
  15. use Blackbit\DataDirectorBundle\lib\Pim\LocationAwareConfigRepository;
  16. use Blackbit\DataDirectorBundle\lib\Pim\Logger\TagLogger;
  17. use Blackbit\DataDirectorBundle\model\Dataport;
  18. use Blackbit\DataDirectorBundle\model\PimcoreDbRepository;
  19. use Blackbit\DataDirectorBundle\Tools\Installer;
  20. use Pimcore\Bundle\AdminBundle\Event\AdminEvents;
  21. use Pimcore\Db;
  22. use Pimcore\Event\Model\DataObject\ClassDefinitionEvent;
  23. use Pimcore\Event\Model\DataObject\ObjectbrickDefinitionEvent;
  24. use Pimcore\File;
  25. use Pimcore\Model\DataObject\ClassDefinition;
  26. use Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage;
  27. use Pimcore\Model\DataObject\ClassDefinition\Data\Image;
  28. use Pimcore\Model\DataObject\ClassDefinition\Data;
  29. use Pimcore\Model\DataObject\ClassDefinition\Data\Objectbricks;
  30. use Pimcore\Model\DataObject\ClassDefinition\Data\Relations\AbstractRelations;
  31. use Pimcore\Model\DataObject\ClassDefinition\Listing;
  32. use Pimcore\Model\DataObject\ClassDefinition\PathFormatterAwareInterface;
  33. use Pimcore\Model\DataObject\Data\ImageGallery;
  34. use Pimcore\Model\DataObject\Objectbrick\Data\AbstractData;
  35. use Pimcore\Model\DataObject\Objectbrick\Definition;
  36. use Pimcore\Perspective\Config;
  37. use Pimcore\Tool;
  38. use Blackbit\DataDirectorBundle\lib\Pim\EventDispatcher;
  39. use Symfony\Component\EventDispatcher\GenericEvent;
  40. class ClassChangedListener
  41. {
  42.     /** @var ItemMoldBuilder */
  43.     private $itemMoldBuilder;
  44.     public function __construct(ItemMoldBuilder $itemMoldBuilder)
  45.     {
  46.         $this->itemMoldBuilder $itemMoldBuilder;
  47.     }
  48.     public function removeCompiledDataQuerySelectors(ClassDefinitionEvent $e) {
  49.         try {
  50.             $dummyObject $this->itemMoldBuilder->getItemMoldByClassname($e->getClassDefinition()->getName());
  51.             $classFqn \get_class($dummyObject);
  52.         } catch (\Exception $classNotFoundException) {
  53.             $classFqn 'Pimcore\\Model\\DataObject\\'.$e->getClassDefinition()->getName();
  54.         }
  55.         $directoryIterator = new \DirectoryIterator(Installer::getCachePath());
  56.         $fileNamePrefix preg_replace('/\W+/''_'$classFqn.' ');
  57.         $filterIterator = new \CallbackFilterIterator($directoryIterator, static function (\SplFileInfo $fileInfo) use ($fileNamePrefix) {
  58.             return strpos($fileInfo->getFilename(), $fileNamePrefix) === || strpos($fileInfo->getFilename(), 'Dao_'.$fileNamePrefix) === || strpos($fileInfo->getFilename(), 'Listing_'.$fileNamePrefix) === 0;
  59.         });
  60.         /** @var \SplFileInfo $compiledFileInfo */
  61.         foreach ($filterIterator as $compiledFile) {
  62.             unlink($compiledFile->getPathname());
  63.         }
  64.     }
  65.     public function removeAllCompiledDataQuerySelectors() {
  66.         /** @var \SplFileInfo $compiledFileInfo */
  67.         foreach(new \DirectoryIterator(Installer::getCachePath()) as $compiledFileInfo) {
  68.             if (!$compiledFileInfo->isDot()) {
  69.                 @unlink($compiledFileInfo->getPathname());
  70.             }
  71.         }
  72.     }
  73.     public function createStoreView(ClassDefinitionEvent $e)
  74.     {
  75.         if ($e->getClassDefinition()->getAllowInherit()) {
  76.             foreach (Tool::getValidLanguages() as $language) {
  77.                 $hasLocalizedFields false;
  78.                 foreach($e->getClassDefinition()->getFieldDefinitions() as $fieldDefinition) {
  79.                     if($fieldDefinition instanceof Localizedfields) {
  80.                         $hasLocalizedFields true;
  81.                         break;
  82.                     }
  83.                 }
  84.                 $query 'CREATE OR REPLACE VIEW `object_localized_store_'.$e->getClassDefinition()->getId().'_'.$language.'` AS SELECT * FROM `object_store_'.$e->getClassDefinition()->getId().'` JOIN `objects` ON `objects`.`'.Helper::prefixObjectSystemColumn('id').'` = `object_store_'.$e->getClassDefinition()->getId().'`.`oo_id`';
  85.                 $parameters = [];
  86.                 if($hasLocalizedFields) {
  87.                     $query .= ' JOIN `object_localized_data_'.$e->getClassDefinition()->getId().'` ON `object_store_'.$e->getClassDefinition()->getId().'`.oo_id=`object_localized_data_'.$e->getClassDefinition()->getId().'`.ooo_id AND language=?';
  88.                     $parameters[] = $language;
  89.                 }
  90.                 PimcoreDbRepository::getInstance()->execute($query$parameters);
  91.             }
  92.         } else {
  93.             $this->removeStoreView($e);
  94.         }
  95.     }
  96.     public function removeStoreView(ClassDefinitionEvent $e)
  97.     {
  98.         foreach (Tool::getValidLanguages() as $language) {
  99.             PimcoreDbRepository::getInstance()->execute('DROP VIEW IF EXISTS `object_localized_store_'.$e->getClassDefinition()->getId().'_'.$language.'`');
  100.         }
  101.     }
  102.     public function addPreviewService(ClassDefinitionEvent $e)
  103.     {
  104.         $classDefinition $e->getClassDefinition();
  105.         if (method_exists($classDefinition'setPreviewGeneratorReference')) {
  106.             if (!$classDefinition->getPreviewGeneratorReference() && !$classDefinition->getLinkGeneratorReference()) {
  107.                 $classDefinition->setPreviewGeneratorReference('@DataDirectorPreview');
  108.             }
  109.         } elseif (method_exists($classDefinition'setPreviewUrl')) {
  110.             if (!$classDefinition->getPreviewUrl()) {
  111.                 $classDefinition->setPreviewUrl('/admin/BlackbitDataDirector/import/object-preview?id=%o_id');
  112.             }
  113.         }
  114.     }
  115.     /**
  116.      * @param ClassDefinitionEvent|ObjectbrickDefinitionEvent $e
  117.      * @return void
  118.      */
  119.     public function setLayoutFieldNames($e)
  120.     {
  121.         if ($e instanceof ObjectbrickDefinitionEvent) {
  122.             $classDefinition $e->getObjectbrickDefinition();
  123.         } else {
  124.             $classDefinition $e->getClassDefinition();
  125.         }
  126.         $layout $classDefinition->getLayoutDefinitions();
  127.         if($layout instanceof ClassDefinition\Layout) {
  128.             $this->setLayoutFieldName($layout$classDefinition);
  129.         }
  130.     }
  131.     /**
  132.      * @param ClassDefinition\Layout|ClassDefinition\Data $layout
  133.      * @param ClassDefinition|Definition $classDefinition
  134.      * @return void
  135.      */
  136.     private function setLayoutFieldName($layout$classDefinition): void
  137.     {
  138.         $translator \Pimcore::getContainer()->get('translator');
  139.         $replaceableLayoutNames = [
  140.             '',
  141.             'Layout',
  142.             $translator->trans($layout->fieldtype, [], 'admin_ext'Tool::getDefaultLanguage()),
  143.             $translator->trans($layout->fieldtype, [], 'admin_ext'Helper::getUser()->getLanguage())
  144.         ];
  145.         if($layout instanceof ClassDefinition\Layout && property_exists($layout'fieldtype') && in_array($layout->name$replaceableLayoutNamestrue)) {
  146.             if($layout->title) {
  147.                 $name trim(preg_replace('/[^a-z0-9_]+/i'''Helper::toASCII($layout->titleTool::getDefaultLanguage())));
  148.                 if(!$classDefinition->getFieldDefinition($name) instanceof ClassDefinition\Data) {
  149.                     $layout->setName($name);
  150.                 }
  151.             } elseif (property_exists($layout'text') && $layout->text) {
  152.                 $name trim(preg_replace('/[^a-z0-9_]+/i'''Helper::toASCII($layout->textTool::getDefaultLanguage())));
  153.                 if (!$classDefinition->getFieldDefinition($name) instanceof ClassDefinition\Data) {
  154.                     $layout->setName($name);
  155.                 }
  156.             }
  157.         }
  158.         if (method_exists($layout'getChildren')) {
  159.             $children $layout->getChildren();
  160.             if (is_array($children)) {
  161.                 foreach ($children as $child) {
  162.                     $this->setLayoutFieldName($child$classDefinition);
  163.                 }
  164.             }
  165.         }
  166.     }
  167.     /**
  168.      * @param ClassDefinitionEvent|ObjectbrickDefinitionEvent $e
  169.      * @return void
  170.      */
  171.     public function addPathFormatterService($e)
  172.     {
  173.         if($e instanceof ObjectbrickDefinitionEvent) {
  174.             $classDefinition $e->getObjectbrickDefinition();
  175.         } else {
  176.             $classDefinition $e->getClassDefinition();
  177.         }
  178.         foreach ($classDefinition->getFieldDefinitions() as $fieldDefinition) {
  179.             if ($fieldDefinition instanceof PathFormatterAwareInterface && !$fieldDefinition->getPathFormatterClass() && method_exists($fieldDefinition'setPathFormatterClass')) {
  180.                 $fieldDefinition->setPathFormatterClass('@DataDirectorSearchViewPathFormatter');
  181.             } elseif ($fieldDefinition instanceof Localizedfields) {
  182.                 foreach ($fieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  183.                     if ($localizedFieldDefinition instanceof PathFormatterAwareInterface && !$localizedFieldDefinition->getPathFormatterClass() && method_exists($localizedFieldDefinition'setPathFormatterClass')) {
  184.                         $localizedFieldDefinition->setPathFormatterClass('@DataDirectorSearchViewPathFormatter');
  185.                     }
  186.                 }
  187.             }
  188.         }
  189.     }
  190.     /**
  191.      * @param ClassDefinitionEvent|ObjectbrickDefinitionEvent $e
  192.      * @return void
  193.      */
  194.     public function clearCalculatedValueFieldCache($e)
  195.     {
  196.         if ($e instanceof ObjectbrickDefinitionEvent) {
  197.             $classDefinition $e->getObjectbrickDefinition();
  198.         } else {
  199.             $classDefinition $e->getClassDefinition();
  200.         }
  201.         foreach ($classDefinition->getFieldDefinitions() as $fieldDefinition) {
  202.             if ($fieldDefinition instanceof CalculatedValueDataQuerySelector) {
  203.                 PimcoreDbRepository::getInstance()->execute('UPDATE object_query_'.$classDefinition->getId().' SET '.Db::get()->quoteIdentifier($fieldDefinition->getName()).'=NULL');
  204.             } elseif ($fieldDefinition instanceof Localizedfields) {
  205.                 foreach ($fieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  206.                     if ($localizedFieldDefinition instanceof CalculatedValueDataQuerySelector) {
  207.                         foreach (Tool::getValidLanguages() as $language) {
  208.                             PimcoreDbRepository::getInstance()->execute('UPDATE object_localized_query_'.$classDefinition->getId().'_'.$language.' SET '.Db::get()->quoteIdentifier($localizedFieldDefinition->getName()).'=NULL');
  209.                         }
  210.                     }
  211.                 }
  212.             }
  213.         }
  214.     }
  215.     
  216.     public function setClassIcon(ClassDefinitionEvent $e)
  217.     {
  218.         $classDefinition $e->getClassDefinition();
  219.         if(!$classDefinition->getIcon()) {
  220.             $icons = ['00_purple.svg''01_magenta.svg''02_red.svg''03_vermilion.svg''04_orange.svg''05_amber.svg''06_yellow.svg''07_chartreuse.svg','08_green.svg''09_teal.svg''10_blue.svg''11_violet.svg'];
  221.             
  222.             $classDefinition->setIcon('/bundles/pimcoreadmin/img/object-icons/'.$icons[crc32($classDefinition->getName()) % count($icons)]);
  223.         }
  224.     }
  225.     public function updatePerspective(ClassDefinitionEvent $e)
  226.     {
  227.         self::createPerspective();
  228.     }
  229.     public static function createPerspective()
  230.     {
  231.         $existingPerspectives Config::get();
  232.         if(!$existingPerspectives) {
  233.             return;
  234.         }
  235.         if($existingPerspectives instanceof \Pimcore\Config\Config) {
  236.             $existingPerspectives $existingPerspectives->toArray();
  237.         }
  238.         foreach($existingPerspectives as $perspectiveName => $existingPerspective) {
  239.             if(strpos($perspectiveName'pim.perspective') !== && $perspectiveName !== 'default') {
  240.                 return;
  241.             }
  242.         }
  243.         $dependencies = [];
  244.         $customViews = [];
  245.         foreach ((new Listing())->load() as $classDefinition) {
  246.             $folders PimcoreDbRepository::getInstance()->findColumnInSql('SELECT DISTINCT '.Helper::prefixObjectSystemColumn('path').' FROM objects WHERE '.Helper::prefixObjectSystemColumn('classId').'=? ORDER BY '.Helper::prefixObjectSystemColumn('path'), [$classDefinition->getId()]);
  247.             if (count($folders) === 0) {
  248.                 $folders = ['/'];
  249.             }
  250.             $firstFolder $folders[0];
  251.             $lastFolder $folders[count($folders) - 1];
  252.             $len min(mb_strlen($firstFolder), mb_strlen($lastFolder));
  253.             for ($i 0$i $len$i++) {
  254.                 if (mb_substr($firstFolder$i1) !== mb_substr($lastFolder$i1)) {
  255.                     break;
  256.                 }
  257.             }
  258.             $commonPrefix substr($firstFolder0$i);
  259.             $customViewId 'dd_'.File::getValidFilename($classDefinition->getGroup() ?? '');
  260.             if (!isset($dependencies[$customViewId])) {
  261.                 $dependencies[$customViewId] = [];
  262.             }
  263.             if (!isset($customViews[$customViewId])) {
  264.                 $customViews[$customViewId] = [
  265.                     'id' => $customViewId,
  266.                     'name' => $classDefinition->getGroup() ?: 'data_objects',
  267.                     'treetype' => 'object',
  268.                     'position' => 'left',
  269.                     'rootfolder' => $commonPrefix ?: '/',
  270.                     'classes' => $classDefinition->getId(),
  271.                     'showroot' => true,
  272.                     'sort' => 0,
  273.                     'treeContextMenu' => [
  274.                         'object' => [
  275.                             'items' => [
  276.                                 'add' => true,
  277.                                 'addFolder' => true,
  278.                                 'importCsv' => true,
  279.                                 'cut' => true,
  280.                                 'copy' => true,
  281.                                 'paste' => true,
  282.                                 'delete' => true,
  283.                                 'rename' => true,
  284.                                 'reload' => true,
  285.                                 'publish' => true,
  286.                                 'unpublish' => true,
  287.                                 'searchAndMove' => true,
  288.                                 'lock' => true,
  289.                                 'unlock' => true,
  290.                                 'lockAndPropagate' => true,
  291.                                 'unlockAndPropagate' => true,
  292.                                 'changeChildrenSortBy' => true
  293.                             ]
  294.                         ]
  295.                     ],
  296.                     'icon' => $classDefinition->getIcon() ?: '/bundles/pimcoreadmin/img/flat-white-icons/pimcore-main-icon-object.svg',
  297.                     'where' => Helper::prefixObjectSystemColumn('path').' LIKE \''.$commonPrefix.'%\''
  298.                 ];
  299.             } else {
  300.                 $customViews[$customViewId]['classes'] .= ','.$classDefinition->getId();
  301.                 if ($folders[0] !== '/') {
  302.                     $firstFolder = (mb_strlen($customViews[$customViewId]['rootfolder']) <= mb_strlen($commonPrefix) ? $customViews[$customViewId]['rootfolder'] : $commonPrefix);
  303.                     $lastFolder = (mb_strlen($customViews[$customViewId]['rootfolder']) > mb_strlen($commonPrefix) ? $customViews[$customViewId]['rootfolder'] : $commonPrefix);
  304.                     $len min(mb_strlen($firstFolder), mb_strlen($lastFolder));
  305.                     for ($i 0$i $len$i++) {
  306.                         if (mb_substr($firstFolder$i1) !== mb_substr($lastFolder$i1)) {
  307.                             break;
  308.                         }
  309.                     }
  310.                     if ($customViews[$customViewId]['where'] === Helper::prefixObjectSystemColumn('path').' LIKE \'/%\'') {
  311.                         $customViews[$customViewId]['where'] = Helper::prefixObjectSystemColumn('path').' LIKE \''.$commonPrefix.'%\'';
  312.                         $customViews[$customViewId]['rootfolder'] = $commonPrefix;
  313.                     } else {
  314.                         $customViews[$customViewId]['where'] .= ' OR '.Helper::prefixObjectSystemColumn('path').' LIKE \''.$commonPrefix.'%\'';
  315.                         $commonPrefix substr($firstFolder0$i);
  316.                         $customViews[$customViewId]['rootfolder'] = $commonPrefix;
  317.                     }
  318.                 }
  319.             }
  320.             foreach ($classDefinition->getFieldDefinitions() as $fieldDefinition) {
  321.                 if ($fieldDefinition instanceof AbstractRelations && method_exists($fieldDefinition'getDocumentsAllowed') && $fieldDefinition->getDocumentsAllowed()) {
  322.                     $dependencies[$customViewId][] = 'document';
  323.                 } elseif($fieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($fieldDefinition'getObjectsAllowed') && $fieldDefinition->getObjectsAllowed()) {
  324.                     foreach ((array)$fieldDefinition->getClasses() as $allowedClass) {
  325.                         $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  326.                         if($allowedClass instanceof ClassDefinition) {
  327.                             $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup() ?? '');
  328.                         }
  329.                     }
  330.                 } elseif ($fieldDefinition instanceof Localizedfields) {
  331.                     foreach ($fieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  332.                         if ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getDocumentsAllowed') && $localizedFieldDefinition->getDocumentsAllowed()) {
  333.                             $dependencies[$customViewId][] = 'document';
  334.                         } elseif ($localizedFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($localizedFieldDefinition'getObjectsAllowed') && $localizedFieldDefinition->getObjectsAllowed()) {
  335.                             foreach ((array)$localizedFieldDefinition->getClasses() as $allowedClass) {
  336.                                 $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  337.                                 if ($allowedClass instanceof ClassDefinition) {
  338.                                     $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  339.                                 }
  340.                             }
  341.                         }
  342.                     }
  343.                 } elseif ($fieldDefinition instanceof Objectbricks) {
  344.                     foreach ($fieldDefinition->getAllowedTypes() as $brickName) {
  345.                         $brickDefinition Definition::getByKey($brickName);
  346.                         if(!$brickDefinition instanceof Definition) {
  347.                             continue;
  348.                         }
  349.                         foreach ($brickDefinition->getFieldDefinitions() as $brickFieldDefinition) {
  350.                             if ($brickFieldDefinition instanceof Localizedfields) {
  351.                                 foreach ($brickFieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  352.                                     if ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getDocumentsAllowed') && $localizedFieldDefinition->getDocumentsAllowed()) {
  353.                                         $dependencies[$customViewId][] = 'document';
  354.                                     } elseif ($localizedFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($localizedFieldDefinition'getObjectsAllowed') && $localizedFieldDefinition->getObjectsAllowed()) {
  355.                                         foreach ((array)$localizedFieldDefinition->getClasses() as $allowedClass) {
  356.                                             $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  357.                                             if ($allowedClass instanceof ClassDefinition) {
  358.                                                 $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  359.                                             }
  360.                                         }
  361.                                     }
  362.                                 }
  363.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && method_exists($brickFieldDefinition'getDocumentsAllowed') && $brickFieldDefinition->getDocumentsAllowed()) {
  364.                                 $dependencies[$customViewId][] = 'document';
  365.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($brickFieldDefinition'getObjectsAllowed') && $brickFieldDefinition->getObjectsAllowed()) {
  366.                                 foreach ((array)$brickFieldDefinition->getClasses() as $allowedClass) {
  367.                                     $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  368.                                     if ($allowedClass instanceof ClassDefinition) {
  369.                                         $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  370.                                     }
  371.                                 }
  372.                             }
  373.                         }
  374.                     }
  375.                 } elseif ($fieldDefinition instanceof ClassDefinition\Data\Fieldcollections) {
  376.                     foreach ($fieldDefinition->getAllowedTypes() as $brickName) {
  377.                         $brickDefinition \Pimcore\Model\DataObject\Fieldcollection\Definition::getByKey($brickName);
  378.                         foreach ($brickDefinition->getFieldDefinitions() as $brickFieldDefinition) {
  379.                             if ($brickFieldDefinition instanceof Localizedfields) {
  380.                                 foreach ($brickFieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  381.                                     if ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getDocumentsAllowed') && $localizedFieldDefinition->getDocumentsAllowed()) {
  382.                                         $dependencies[$customViewId][] = 'document';
  383.                                     } elseif ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getObjectsAllowed') && $localizedFieldDefinition->getObjectsAllowed()) {
  384.                                         foreach ((array)$localizedFieldDefinition->getClasses() as $allowedClass) {
  385.                                             $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  386.                                             if ($allowedClass instanceof ClassDefinition) {
  387.                                                 $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  388.                                             }
  389.                                         }
  390.                                     }
  391.                                 }
  392.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && method_exists($brickFieldDefinition'getDocumentsAllowed') && $brickFieldDefinition->getDocumentsAllowed()) {
  393.                                 $dependencies[$customViewId][] = 'document';
  394.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($brickFieldDefinition'getObjectsAllowed') && $brickFieldDefinition->getObjectsAllowed()) {
  395.                                 foreach ((array)$brickFieldDefinition->getClasses() as $allowedClass) {
  396.                                     $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  397.                                     if ($allowedClass instanceof ClassDefinition) {
  398.                                         $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  399.                                     }
  400.                                 }
  401.                             }
  402.                         }
  403.                     }
  404.                 }
  405.             }
  406.         }
  407.         $perspectives = [
  408.             'pim.perspective.default' => [
  409.                 'elementTree' => [
  410.                     [
  411.                         'type' => 'documents',
  412.                         'position' => 'left',
  413.                         'expanded' => false,
  414.                         'hidden' => false,
  415.                         'sort' => 0
  416.                     ],
  417.                     [
  418.                         'type' => 'assets',
  419.                         'position' => 'left',
  420.                         'expanded' => false,
  421.                         'hidden' => false,
  422.                         'sort' => 1
  423.                     ],
  424.                     [
  425.                         'type' => 'objects',
  426.                         'position' => 'left',
  427.                         'expanded' => false,
  428.                         'hidden' => false,
  429.                         'sort' => 2
  430.                     ]
  431.                 ],
  432.                 'iconCls' => 'pimcore_nav_icon_perspective',
  433.                 'icon' => null,
  434.                 'dashboards' => [
  435.                     'predefined' => [
  436.                         'welcome' => [
  437.                             'positions' => [
  438.                                 [
  439.                                     [
  440.                                         'id' => 1,
  441.                                         'type' => 'pimcore.layout.portlets.modificationStatistic',
  442.                                         'config' => null
  443.                                     ],
  444.                                     [
  445.                                         'id' => 2,
  446.                                         'type' => 'pimcore.layout.portlets.modifiedAssets',
  447.                                         'config' => null
  448.                                     ]
  449.                                 ],
  450.                                 [
  451.                                     [
  452.                                         'id' => 3,
  453.                                         'type' => 'pimcore.layout.portlets.modifiedObjects',
  454.                                         'config' => null
  455.                                     ],
  456.                                     [
  457.                                         'id' => 4,
  458.                                         'type' => 'pimcore.layout.portlets.modifiedDocuments',
  459.                                         'config' => null
  460.                                     ]
  461.                                 ]
  462.                             ]
  463.                         ]
  464.                     ]
  465.                 ]
  466.             ]
  467.         ];
  468.         if (count($customViews) > 0) {
  469.             foreach($customViews as &$customView) {
  470.                 $foldersInCustomView PimcoreDbRepository::getInstance()->findColumnInSql('SELECT CONCAT('.Helper::prefixObjectSystemColumn('path').',`'.Helper::prefixObjectSystemColumn('key').'`) 
  471.                     FROM objects 
  472.                     WHERE '.Helper::prefixObjectSystemColumn('type').'=\'folder\' 
  473.                     AND '.Helper::prefixObjectSystemColumn('path').' LIKE ?
  474.                     AND `'.Helper::prefixObjectSystemColumn('key').'` != \'\'
  475.                     AND ('.$customView['where'].')',
  476.                     [rtrim($customView['rootfolder'], '/').'/%']
  477.                 );
  478.                 $forbiddenFolders = [];
  479.                 foreach($foldersInCustomView as $folderInCustomView) {
  480.                     $foldersInCustomViewHasObjectsOfAllowedClasses PimcoreDbRepository::getInstance()->findOneInSql('SELECT 1 FROM objects WHERE '.Helper::prefixObjectSystemColumn('path').' LIKE ? AND '.Helper::prefixObjectSystemColumn('type').' != \'folder\' AND '.Helper::prefixObjectSystemColumn('classId').' IN (?) AND ('.$customView['where'].') LIMIT 1', [$folderInCustomView.'/%'explode(','$customView['classes'])]);
  481.                     if(!$foldersInCustomViewHasObjectsOfAllowedClasses) {
  482.                         $foldersInCustomViewHasOtherClassObjects PimcoreDbRepository::getInstance()->findOneInSql(
  483.                             'SELECT 1 FROM objects WHERE '.Helper::prefixObjectSystemColumn('path').' LIKE ? AND '.Helper::prefixObjectSystemColumn('type').' != \'folder\' AND '.Helper::prefixObjectSystemColumn('classId').' NOT IN (?) AND ('.$customView['where'].') LIMIT 1',
  484.                             [rtrim($folderInCustomView'/').'/%'explode(','$customView['classes'])]
  485.                         );
  486.                         if($foldersInCustomViewHasOtherClassObjects) {
  487.                             $forbiddenFolders[] = $folderInCustomView;
  488.                         }
  489.                     }
  490.                 }
  491.                 if($forbiddenFolders) {
  492.                     $customView['where'] = '('.$customView['where'].') AND CONCAT('.Helper::prefixObjectSystemColumn('path').', `'.Helper::prefixObjectSystemColumn('key').'`) NOT IN (\''.implode('\',\''$forbiddenFolders).'\')';
  493.                 }
  494.             }
  495.             unset($customView);
  496.             self::saveCustomView($customViews);
  497.             uksort($customViews, static function ($customViewId1$customViewId2) use ($customViews$dependencies) {
  498.                 $order count($dependencies[$customViewId2]) <=> count($dependencies[$customViewId1]);
  499.                 if ($order !== 0) {
  500.                     return $order;
  501.                 }
  502.                 $order substr_count($customViews[$customViewId2]['classes'], ',') <=> substr_count($customViews[$customViewId1]['classes'], ',');
  503.                 if ($order !== 0) {
  504.                     return $order;
  505.                 }
  506.                 if ($customViews[$customViewId1]['name'] === 'data_objects' && $customViews[$customViewId2]['name'] !== 'data_objects') {
  507.                     return 1;
  508.                 }
  509.                 if ($customViews[$customViewId1]['name'] !== 'data_objects' && $customViews[$customViewId2]['name'] === 'data_objects') {
  510.                     return -1;
  511.                 }
  512.                 return strcasecmp($customViews[$customViewId1]['name'], $customViews[$customViewId2]['name']);
  513.             });
  514.             $elementTree = [[
  515.                 'type' => 'assets',
  516.                 'position' => 'right',
  517.                 'expanded' => false,
  518.                 'hidden' => false,
  519.                 'sort' => 9000
  520.             ]];
  521.             foreach ($customViews as $customViewId => $customView) {
  522.                 if (in_array('document'$dependencies[$customViewId], true)) {
  523.                     $elementTree[] = [
  524.                         'type' => 'documents',
  525.                         'position' => 'left',
  526.                         'expanded' => false,
  527.                         'hidden' => false,
  528.                         'sort' => 9001
  529.                     ];
  530.                 }
  531.             }
  532.             $index 0;
  533.             foreach ($customViews as $customViewId => $customView) {
  534.                 $position 'left';
  535.                 foreach ($elementTree as $perspectiveView) {
  536.                     if ($perspectiveView['type'] === 'customview' && in_array($customViewId$dependencies[$perspectiveView['id']] ?? [])) {
  537.                         $position 'right';
  538.                         break;
  539.                     }
  540.                 }
  541.                 $elementTree[] = [
  542.                     'type' => 'customview',
  543.                     'position' => $position,
  544.                     'expanded' => false,
  545.                     'hidden' => false,
  546.                     'sort' => $customViewId === 'dd_' 8000 : ($index++),
  547.                     'id' => $customViewId
  548.                 ];
  549.             }
  550.             $perspectives['pim.perspective.PIM'] = [
  551.                 'iconCls' => 'pimcore_icon_object',
  552.                 'elementTree' => $elementTree,
  553.                 'dashboards' => [
  554.                     'predefined' => [
  555.                         'welcome' => [
  556.                             'positions' => [
  557.                                 [
  558.                                     [
  559.                                         'id' => 1,
  560.                                         'type' => 'pimcore.layout.portlets.DataDirector_ErrorMonitor',
  561.                                         'config' => null
  562.                                     ],
  563.                                     [
  564.                                         'id' => 2,
  565.                                         'type' => 'pimcore.layout.portlets.DataDirector_TaggedElements',
  566.                                         'config' => json_encode([
  567.                                             'title' => 'Objects with import errors',
  568.                                             'tags' => [TagLogger::getOrCreateTag('Data Director')->getId()]
  569.                                         ])
  570.                                     ]
  571.                                 ],
  572.                                 [
  573.                                     [
  574.                                         'id' => 3,
  575.                                         'type' => 'pimcore.layout.portlets.DataDirector_QueueMonitor',
  576.                                         'config' => null
  577.                                     ]
  578.                                 ]
  579.                             ]
  580.                         ]
  581.                     ]
  582.                 ]
  583.             ];
  584.         }
  585.         self::savePerspective($perspectives);
  586.     }
  587.     private static function savePerspective(array $data) {
  588.         $containerConfig \Pimcore::getContainer()->getParameter('pimcore.config');
  589.         $config $containerConfig['perspectives']['definitions'];
  590.         if (method_exists(\Pimcore\Config\LocationAwareConfigRepository::class, 'getStorageConfigurationCompatibilityLayer')) {
  591.             $storageConfig \Pimcore\Config\LocationAwareConfigRepository::getStorageConfigurationCompatibilityLayer(
  592.                 $containerConfig,
  593.                 'perspectives',
  594.                 'PIMCORE_CONFIG_STORAGE_DIR_PERSPECTIVES',
  595.                 'PIMCORE_WRITE_TARGET_PERSPECTIVES'
  596.             );
  597.         } else {
  598.             $storageConfig $containerConfig['config_location']['perspectives'] ?? null;
  599.         }
  600.         if (empty($storageConfig['write_target']['options']['directory'])) {
  601.             $storageConfig['write_target']['options']['directory'] = PIMCORE_CONFIGURATION_DIRECTORY.'/perspectives';
  602.         }
  603.         try {
  604.             $repository = new LocationAwareConfigRepository(
  605.                 $config,
  606.                 'pimcore_perspectives',
  607.                 $storageConfig
  608.             );
  609.         } catch (\Throwable $e) {
  610.             $repository = new LocationAwareConfigRepository(
  611.                 $config,
  612.                 'pimcore_perspectives',
  613.                 $storageConfig['write_target']['options']['directory'],
  614.                 null
  615.             );
  616.         }
  617.         foreach ($data as $key => $value) {
  618.             list($configKey$dataSource) = $repository->loadConfigByKey($key);
  619.             if ($repository->isWriteable($key$dataSource) === true) {
  620.                 unset($value['writeable']);
  621.                 $repository->saveConfig($key$value, function ($key$data) {
  622.                     return [
  623.                         'pimcore' => [
  624.                             'perspectives' => [
  625.                                 'definitions' => [
  626.                                     $key => $data,
  627.                                 ],
  628.                             ],
  629.                         ],
  630.                     ];
  631.                 });
  632.             }
  633.         }
  634.     }
  635.     private static function saveCustomView(array $data)
  636.     {
  637.         $containerConfig \Pimcore::getContainer()->getParameter('pimcore.config');
  638.         $config $containerConfig['custom_views']['definitions'];
  639.         if (method_exists(\Pimcore\Config\LocationAwareConfigRepository::class, 'getStorageConfigurationCompatibilityLayer')) {
  640.             $storageConfig \Pimcore\Config\LocationAwareConfigRepository::getStorageConfigurationCompatibilityLayer(
  641.                 $containerConfig,
  642.                 'custom_views',
  643.                 'PIMCORE_CONFIG_STORAGE_DIR_CUSTOM_VIEWS',
  644.                 'PIMCORE_WRITE_TARGET_CUSTOM_VIEWS'
  645.             );
  646.         } else {
  647.             $storageConfig $containerConfig['config_location']['custom_views'] ?? null;
  648.         }
  649.         if(empty($storageConfig['write_target']['options']['directory'])) {
  650.             $storageConfig['write_target']['options']['directory'] = PIMCORE_CONFIGURATION_DIRECTORY.'/custom-views';
  651.         }
  652.         try {
  653.             $repository = new LocationAwareConfigRepository(
  654.                 $config,
  655.                 'pimcore_custom_views',
  656.                 $storageConfig
  657.             );
  658.         } catch(\Throwable $e) {
  659.             $repository = new LocationAwareConfigRepository(
  660.                 $config,
  661.                 'pimcore_custom_views',
  662.                 $storageConfig['write_target']['options']['directory'],
  663.                 null
  664.             );
  665.         }
  666.         foreach ($data as $key => $value) {
  667.             $key = (string)$key;
  668.             list($configKey$dataSource) = $repository->loadConfigByKey($key);
  669.             if ($repository->isWriteable($key$dataSource)) {
  670.                 unset($value['writeable']);
  671.                 $repository->saveConfig($key$value, function ($key$data) {
  672.                     return [
  673.                         'pimcore' => [
  674.                             'custom_views' => [
  675.                                 'definitions' => [
  676.                                     $key => $data,
  677.                                 ],
  678.                             ],
  679.                         ],
  680.                     ];
  681.                 });
  682.             }
  683.         }
  684.     }
  685. }