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

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\Helper;
  13. use Blackbit\DataDirectorBundle\lib\Pim\Item\ItemMoldBuilder;
  14. use Blackbit\DataDirectorBundle\lib\Pim\LocationAwareConfigRepository;
  15. use Blackbit\DataDirectorBundle\lib\Pim\Logger\TagLogger;
  16. use Blackbit\DataDirectorBundle\model\Dataport;
  17. use Blackbit\DataDirectorBundle\model\PimcoreDbRepository;
  18. use Blackbit\DataDirectorBundle\Tools\Installer;
  19. use Pimcore\Event\Model\DataObject\ClassDefinitionEvent;
  20. use Pimcore\Event\Model\DataObject\ObjectbrickDefinitionEvent;
  21. use Pimcore\File;
  22. use Pimcore\Model\DataObject\ClassDefinition;
  23. use Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage;
  24. use Pimcore\Model\DataObject\ClassDefinition\Data\Image;
  25. use Pimcore\Model\DataObject\ClassDefinition\Data\Localizedfields;
  26. use Pimcore\Model\DataObject\ClassDefinition\Data\Objectbricks;
  27. use Pimcore\Model\DataObject\ClassDefinition\Data\Relations\AbstractRelations;
  28. use Pimcore\Model\DataObject\ClassDefinition\Listing;
  29. use Pimcore\Model\DataObject\ClassDefinition\PathFormatterAwareInterface;
  30. use Pimcore\Model\DataObject\Data\ImageGallery;
  31. use Pimcore\Model\DataObject\Objectbrick\Data\AbstractData;
  32. use Pimcore\Model\DataObject\Objectbrick\Definition;
  33. use Pimcore\Perspective\Config;
  34. use Pimcore\Tool;
  35. class ClassChangedListener
  36. {
  37.     /** @var ItemMoldBuilder */
  38.     private $itemMoldBuilder;
  39.     public function __construct(ItemMoldBuilder $itemMoldBuilder)
  40.     {
  41.         $this->itemMoldBuilder $itemMoldBuilder;
  42.     }
  43.     public function removeCompiledDataQuerySelectors(ClassDefinitionEvent $e) {
  44.         try {
  45.             $dummyObject $this->itemMoldBuilder->getItemMoldByClassname($e->getClassDefinition()->getName());
  46.             $classFqn \get_class($dummyObject);
  47.         } catch (\Exception $classNotFoundException) {
  48.             $classFqn 'Pimcore\\Model\\DataObject\\'.$e->getClassDefinition()->getName();
  49.         }
  50.         $directoryIterator = new \DirectoryIterator(Installer::getCachePath());
  51.         $fileNamePrefix preg_replace('/\W+/''_'$classFqn.' ');
  52.         $filterIterator = new \CallbackFilterIterator($directoryIterator, static function (\SplFileInfo $fileInfo) use ($fileNamePrefix) {
  53.             return strpos($fileInfo->getFilename(), $fileNamePrefix) === || strpos($fileInfo->getFilename(), 'Dao_'.$fileNamePrefix) === || strpos($fileInfo->getFilename(), 'Listing_'.$fileNamePrefix) === 0;
  54.         });
  55.         /** @var \SplFileInfo $compiledFileInfo */
  56.         foreach ($filterIterator as $compiledFile) {
  57.             unlink($compiledFile->getPathname());
  58.         }
  59.     }
  60.     public function removeAllCompiledDataQuerySelectors() {
  61.         /** @var \SplFileInfo $compiledFileInfo */
  62.         foreach(new \DirectoryIterator(Installer::getCachePath()) as $compiledFileInfo) {
  63.             if (!$compiledFileInfo->isDot()) {
  64.                 @unlink($compiledFileInfo->getPathname());
  65.             }
  66.         }
  67.     }
  68.     public function createStoreView(ClassDefinitionEvent $e)
  69.     {
  70.         if ($e->getClassDefinition()->getAllowInherit()) {
  71.             foreach (Tool::getValidLanguages() as $language) {
  72.                 $hasLocalizedFields false;
  73.                 foreach($e->getClassDefinition()->getFieldDefinitions() as $fieldDefinition) {
  74.                     if($fieldDefinition instanceof Localizedfields) {
  75.                         $hasLocalizedFields true;
  76.                         break;
  77.                     }
  78.                 }
  79.                 $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`';
  80.                 $parameters = [];
  81.                 if($hasLocalizedFields) {
  82.                     $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=?';
  83.                     $parameters[] = $language;
  84.                 }
  85.                 PimcoreDbRepository::getInstance()->execute($query$parameters);
  86.             }
  87.         } else {
  88.             $this->removeStoreView($e);
  89.         }
  90.     }
  91.     public function removeStoreView(ClassDefinitionEvent $e)
  92.     {
  93.         foreach (Tool::getValidLanguages() as $language) {
  94.             PimcoreDbRepository::getInstance()->execute('DROP VIEW IF EXISTS `object_localized_store_'.$e->getClassDefinition()->getId().'_'.$language.'`');
  95.         }
  96.     }
  97.     public function addPreviewService(ClassDefinitionEvent $e)
  98.     {
  99.         $classDefinition $e->getClassDefinition();
  100.         if (method_exists($classDefinition'setPreviewGeneratorReference')) {
  101.             if (!$classDefinition->getPreviewGeneratorReference()) {
  102.                 $classDefinition->setPreviewGeneratorReference('@DataDirectorPreview');
  103.             }
  104.         } elseif (method_exists($classDefinition'setPreviewUrl')) {
  105.             if (!$classDefinition->getPreviewUrl()) {
  106.                 $classDefinition->setPreviewUrl('/admin/BlackbitDataDirector/import/object-preview?id=%o_id');
  107.             }
  108.         }
  109.     }
  110.     /**
  111.      * @param ClassDefinitionEvent|ObjectbrickDefinitionEvent $e
  112.      * @return void
  113.      */
  114.     public function addPathFormatterService($e)
  115.     {
  116.         if($e instanceof ObjectbrickDefinitionEvent) {
  117.             $classDefinition $e->getObjectbrickDefinition();
  118.         } else {
  119.             $classDefinition $e->getClassDefinition();
  120.         }
  121.         foreach ($classDefinition->getFieldDefinitions() as $fieldDefinition) {
  122.             if ($fieldDefinition instanceof PathFormatterAwareInterface && !$fieldDefinition->getPathFormatterClass() && method_exists($fieldDefinition'setPathFormatterClass')) {
  123.                 $fieldDefinition->setPathFormatterClass('@DataDirectorSearchViewPathFormatter');
  124.             } elseif ($fieldDefinition instanceof Localizedfields) {
  125.                 foreach ($fieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  126.                     if ($localizedFieldDefinition instanceof PathFormatterAwareInterface && !$localizedFieldDefinition->getPathFormatterClass() && method_exists($localizedFieldDefinition'setPathFormatterClass')) {
  127.                         $localizedFieldDefinition->setPathFormatterClass('@DataDirectorSearchViewPathFormatter');
  128.                     }
  129.                 }
  130.             }
  131.         }
  132.     }
  133.     public function updatePerspective(ClassDefinitionEvent $e)
  134.     {
  135.         self::createPerspective();
  136.     }
  137.     public static function createPerspective()
  138.     {
  139.         $existingPerspectives Config::get();
  140.         if(!$existingPerspectives) {
  141.             return;
  142.         }
  143.         if($existingPerspectives instanceof \Pimcore\Config\Config) {
  144.             $existingPerspectives $existingPerspectives->toArray();
  145.         }
  146.         foreach($existingPerspectives as $perspectiveName => $existingPerspective) {
  147.             if(strpos($perspectiveName'pim.perspective') !== && $perspectiveName !== 'default') {
  148.                 return;
  149.             }
  150.         }
  151.         $dependencies = [];
  152.         $customViews = [];
  153.         foreach ((new Listing())->load() as $classDefinition) {
  154.             $folders PimcoreDbRepository::getInstance()->findColumnInSql('SELECT DISTINCT '.Helper::prefixObjectSystemColumn('path').' FROM objects WHERE '.Helper::prefixObjectSystemColumn('classId').'=? ORDER BY '.Helper::prefixObjectSystemColumn('path'), [$classDefinition->getId()]);
  155.             if (count($folders) === 0) {
  156.                 $folders = ['/'];
  157.             }
  158.             $firstFolder $folders[0];
  159.             $lastFolder $folders[count($folders) - 1];
  160.             $len min(mb_strlen($firstFolder), mb_strlen($lastFolder));
  161.             for ($i 0$i $len$i++) {
  162.                 if (mb_substr($firstFolder$i1) !== mb_substr($lastFolder$i1)) {
  163.                     break;
  164.                 }
  165.             }
  166.             $commonPrefix substr($firstFolder0$i);
  167.             $customViewId 'dd_'.File::getValidFilename($classDefinition->getGroup() ?? '');
  168.             if (!isset($dependencies[$customViewId])) {
  169.                 $dependencies[$customViewId] = [];
  170.             }
  171.             if (!isset($customViews[$customViewId])) {
  172.                 $customViews[$customViewId] = [
  173.                     'id' => $customViewId,
  174.                     'name' => $classDefinition->getGroup() ?: 'data_objects',
  175.                     'treetype' => 'object',
  176.                     'position' => 'left',
  177.                     'rootfolder' => $commonPrefix ?: '/',
  178.                     'classes' => $classDefinition->getId(),
  179.                     'showroot' => true,
  180.                     'sort' => 0,
  181.                     'treeContextMenu' => [
  182.                         'object' => [
  183.                             'items' => [
  184.                                 'add' => true,
  185.                                 'addFolder' => true,
  186.                                 'importCsv' => true,
  187.                                 'cut' => true,
  188.                                 'copy' => true,
  189.                                 'paste' => true,
  190.                                 'delete' => true,
  191.                                 'rename' => true,
  192.                                 'reload' => true,
  193.                                 'publish' => true,
  194.                                 'unpublish' => true,
  195.                                 'searchAndMove' => true,
  196.                                 'lock' => true,
  197.                                 'unlock' => true,
  198.                                 'lockAndPropagate' => true,
  199.                                 'unlockAndPropagate' => true,
  200.                                 'changeChildrenSortBy' => true
  201.                             ]
  202.                         ]
  203.                     ],
  204.                     'icon' => $classDefinition->getIcon() ?: '/bundles/pimcoreadmin/img/flat-white-icons/pimcore-main-icon-object.svg',
  205.                     'where' => Helper::prefixObjectSystemColumn('path').' LIKE \''.$commonPrefix.'%\''
  206.                 ];
  207.             } else {
  208.                 $customViews[$customViewId]['classes'] .= ','.$classDefinition->getId();
  209.                 $firstFolder = (mb_strlen($customViews[$customViewId]['rootfolder']) <= mb_strlen($commonPrefix) ? $customViews[$customViewId]['rootfolder'] : $commonPrefix);
  210.                 $lastFolder = (mb_strlen($customViews[$customViewId]['rootfolder']) > mb_strlen($commonPrefix) ? $customViews[$customViewId]['rootfolder'] : $commonPrefix);
  211.                 $len min(mb_strlen($firstFolder), mb_strlen($lastFolder));
  212.                 for ($i 0$i $len$i++) {
  213.                     if (mb_substr($firstFolder$i1) !== mb_substr($lastFolder$i1)) {
  214.                         break;
  215.                     }
  216.                 }
  217.                 $customViews[$customViewId]['where'] .= ' OR '.Helper::prefixObjectSystemColumn('path').' LIKE \''.$commonPrefix.'%\'';
  218.                 $commonPrefix substr($firstFolder0$i);
  219.                 $customViews[$customViewId]['rootfolder'] = $commonPrefix;
  220.             }
  221.             foreach ($classDefinition->getFieldDefinitions() as $fieldDefinition) {
  222.                 if ($fieldDefinition instanceof AbstractRelations && method_exists($fieldDefinition'getDocumentsAllowed') && $fieldDefinition->getDocumentsAllowed()) {
  223.                     $dependencies[$customViewId][] = 'document';
  224.                 } elseif($fieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($fieldDefinition'getObjectsAllowed') && $fieldDefinition->getObjectsAllowed()) {
  225.                     foreach ((array)$fieldDefinition->getClasses() as $allowedClass) {
  226.                         $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  227.                         if($allowedClass instanceof ClassDefinition) {
  228.                             $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup() ?? '');
  229.                         }
  230.                     }
  231.                 } elseif ($fieldDefinition instanceof Localizedfields) {
  232.                     foreach ($fieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  233.                         if ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getDocumentsAllowed') && $localizedFieldDefinition->getDocumentsAllowed()) {
  234.                             $dependencies[$customViewId][] = 'document';
  235.                         } elseif ($localizedFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($localizedFieldDefinition'getObjectsAllowed') && $localizedFieldDefinition->getObjectsAllowed()) {
  236.                             foreach ((array)$localizedFieldDefinition->getClasses() as $allowedClass) {
  237.                                 $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  238.                                 if ($allowedClass instanceof ClassDefinition) {
  239.                                     $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  240.                                 }
  241.                             }
  242.                         }
  243.                     }
  244.                 } elseif ($fieldDefinition instanceof Objectbricks) {
  245.                     foreach ($fieldDefinition->getAllowedTypes() as $brickName) {
  246.                         $brickDefinition Definition::getByKey($brickName);
  247.                         if(!$brickDefinition instanceof Definition) {
  248.                             continue;
  249.                         }
  250.                         foreach ($brickDefinition->getFieldDefinitions() as $brickFieldDefinition) {
  251.                             if ($brickFieldDefinition instanceof Localizedfields) {
  252.                                 foreach ($brickFieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  253.                                     if ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getDocumentsAllowed') && $localizedFieldDefinition->getDocumentsAllowed()) {
  254.                                         $dependencies[$customViewId][] = 'document';
  255.                                     } elseif ($localizedFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($localizedFieldDefinition'getObjectsAllowed') && $localizedFieldDefinition->getObjectsAllowed()) {
  256.                                         foreach ((array)$localizedFieldDefinition->getClasses() as $allowedClass) {
  257.                                             $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  258.                                             if ($allowedClass instanceof ClassDefinition) {
  259.                                                 $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  260.                                             }
  261.                                         }
  262.                                     }
  263.                                 }
  264.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && method_exists($brickFieldDefinition'getDocumentsAllowed') && $brickFieldDefinition->getDocumentsAllowed()) {
  265.                                 $dependencies[$customViewId][] = 'document';
  266.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($brickFieldDefinition'getObjectsAllowed') && $brickFieldDefinition->getObjectsAllowed()) {
  267.                                 foreach ((array)$brickFieldDefinition->getClasses() as $allowedClass) {
  268.                                     $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  269.                                     if ($allowedClass instanceof ClassDefinition) {
  270.                                         $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  271.                                     }
  272.                                 }
  273.                             }
  274.                         }
  275.                     }
  276.                 } elseif ($fieldDefinition instanceof ClassDefinition\Data\Fieldcollections) {
  277.                     foreach ($fieldDefinition->getAllowedTypes() as $brickName) {
  278.                         $brickDefinition \Pimcore\Model\DataObject\Fieldcollection\Definition::getByKey($brickName);
  279.                         foreach ($brickDefinition->getFieldDefinitions() as $brickFieldDefinition) {
  280.                             if ($brickFieldDefinition instanceof Localizedfields) {
  281.                                 foreach ($brickFieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  282.                                     if ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getDocumentsAllowed') && $localizedFieldDefinition->getDocumentsAllowed()) {
  283.                                         $dependencies[$customViewId][] = 'document';
  284.                                     } elseif ($localizedFieldDefinition instanceof AbstractRelations && method_exists($localizedFieldDefinition'getObjectsAllowed') && $localizedFieldDefinition->getObjectsAllowed()) {
  285.                                         foreach ((array)$localizedFieldDefinition->getClasses() as $allowedClass) {
  286.                                             $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  287.                                             if ($allowedClass instanceof ClassDefinition) {
  288.                                                 $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  289.                                             }
  290.                                         }
  291.                                     }
  292.                                 }
  293.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && method_exists($brickFieldDefinition'getDocumentsAllowed') && $brickFieldDefinition->getDocumentsAllowed()) {
  294.                                 $dependencies[$customViewId][] = 'document';
  295.                             } elseif ($brickFieldDefinition instanceof AbstractRelations && !$fieldDefinition instanceof ClassDefinition\Data\ReverseManyToManyObjectRelation && !$fieldDefinition instanceof ClassDefinition\Data\ReverseObjectRelation && method_exists($brickFieldDefinition'getObjectsAllowed') && $brickFieldDefinition->getObjectsAllowed()) {
  296.                                 foreach ((array)$brickFieldDefinition->getClasses() as $allowedClass) {
  297.                                     $allowedClass ClassDefinition::getByName($allowedClass['classes']);
  298.                                     if ($allowedClass instanceof ClassDefinition) {
  299.                                         $dependencies[$customViewId][] = 'dd_'.File::getValidFilename($allowedClass->getGroup());
  300.                                     }
  301.                                 }
  302.                             }
  303.                         }
  304.                     }
  305.                 }
  306.             }
  307.         }
  308.         $perspectives = [
  309.             'pim.perspective.default' => [
  310.                 'elementTree' => [
  311.                     [
  312.                         'type' => 'documents',
  313.                         'position' => 'left',
  314.                         'expanded' => false,
  315.                         'hidden' => false,
  316.                         'sort' => 2
  317.                     ],
  318.                     [
  319.                         'type' => 'assets',
  320.                         'position' => 'left',
  321.                         'expanded' => false,
  322.                         'hidden' => false,
  323.                         'sort' => 1
  324.                     ],
  325.                     [
  326.                         'type' => 'objects',
  327.                         'position' => 'left',
  328.                         'expanded' => false,
  329.                         'hidden' => false,
  330.                         'sort' => 0
  331.                     ]
  332.                 ],
  333.                 'iconCls' => 'pimcore_nav_icon_perspective',
  334.                 'icon' => null,
  335.                 'dashboards' => [
  336.                     'predefined' => [
  337.                         'welcome' => [
  338.                             'positions' => [
  339.                                 [
  340.                                     [
  341.                                         'id' => 1,
  342.                                         'type' => 'pimcore.layout.portlets.modificationStatistic',
  343.                                         'config' => null
  344.                                     ],
  345.                                     [
  346.                                         'id' => 2,
  347.                                         'type' => 'pimcore.layout.portlets.modifiedAssets',
  348.                                         'config' => null
  349.                                     ]
  350.                                 ],
  351.                                 [
  352.                                     [
  353.                                         'id' => 3,
  354.                                         'type' => 'pimcore.layout.portlets.modifiedObjects',
  355.                                         'config' => null
  356.                                     ],
  357.                                     [
  358.                                         'id' => 4,
  359.                                         'type' => 'pimcore.layout.portlets.modifiedDocuments',
  360.                                         'config' => null
  361.                                     ]
  362.                                 ]
  363.                             ]
  364.                         ]
  365.                     ]
  366.                 ]
  367.             ]
  368.         ];
  369.         if (count($customViews) > 0) {
  370.             self::saveCustomView($customViews);
  371.             uksort($customViews, static function ($customViewId1$customViewId2) use ($customViews$dependencies) {
  372.                 $order count($dependencies[$customViewId2]) <=> count($dependencies[$customViewId1]);
  373.                 if ($order !== 0) {
  374.                     return $order;
  375.                 }
  376.                 $order substr_count($customViews[$customViewId2]['classes'], ',') <=> substr_count($customViews[$customViewId1]['classes'], ',');
  377.                 if ($order !== 0) {
  378.                     return $order;
  379.                 }
  380.                 if ($customViews[$customViewId1]['name'] === 'data_objects' && $customViews[$customViewId2]['name'] !== 'data_objects') {
  381.                     return 1;
  382.                 }
  383.                 if ($customViews[$customViewId1]['name'] !== 'data_objects' && $customViews[$customViewId2]['name'] === 'data_objects') {
  384.                     return -1;
  385.                 }
  386.                 return strcasecmp($customViews[$customViewId1]['name'], $customViews[$customViewId2]['name']);
  387.             });
  388.             $elementTree = [[
  389.                 'type' => 'assets',
  390.                 'position' => 'right',
  391.                 'expanded' => false,
  392.                 'hidden' => false,
  393.                 'sort' => 9000
  394.             ]];
  395.             foreach ($customViews as $customViewId => $customView) {
  396.                 if (in_array('document'$dependencies[$customViewId], true)) {
  397.                     $elementTree[] = [
  398.                         'type' => 'documents',
  399.                         'position' => 'left',
  400.                         'expanded' => false,
  401.                         'hidden' => false,
  402.                         'sort' => 9001
  403.                     ];
  404.                 }
  405.             }
  406.             $index 0;
  407.             foreach ($customViews as $customViewId => $customView) {
  408.                 $position 'left';
  409.                 foreach ($elementTree as $perspectiveView) {
  410.                     if ($perspectiveView['type'] === 'customview' && in_array($customViewId$dependencies[$perspectiveView['id']] ?? [])) {
  411.                         $position 'right';
  412.                         break;
  413.                     }
  414.                 }
  415.                 $elementTree[] = [
  416.                     'type' => 'customview',
  417.                     'position' => $position,
  418.                     'expanded' => false,
  419.                     'hidden' => false,
  420.                     'sort' => $customViewId === 'dd_' 8000 : ($index++),
  421.                     'id' => $customViewId
  422.                 ];
  423.             }
  424.             $perspectives['pim.perspective.PIM'] = [
  425.                 'iconCls' => 'pimcore_icon_object',
  426.                 'elementTree' => $elementTree,
  427.                 'dashboards' => [
  428.                     'predefined' => [
  429.                         'welcome' => [
  430.                             'positions' => [
  431.                                 [
  432.                                     [
  433.                                         'id' => 1,
  434.                                         'type' => 'pimcore.layout.portlets.DataDirector_ErrorMonitor',
  435.                                         'config' => null
  436.                                     ],
  437.                                     [
  438.                                         'id' => 2,
  439.                                         'type' => 'pimcore.layout.portlets.DataDirector_TaggedElements',
  440.                                         'config' => json_encode([
  441.                                             'title' => 'Objects with import errors',
  442.                                             'tags' => [TagLogger::getOrCreateTag('Data Director')->getId()]
  443.                                         ])
  444.                                     ]
  445.                                 ],
  446.                                 [
  447.                                     [
  448.                                         'id' => 3,
  449.                                         'type' => 'pimcore.layout.portlets.DataDirector_QueueMonitor',
  450.                                         'config' => null
  451.                                     ]
  452.                                 ]
  453.                             ]
  454.                         ]
  455.                     ]
  456.                 ]
  457.             ];
  458.         }
  459.         self::savePerspective($perspectives);
  460.     }
  461.     private static function savePerspective(array $data) {
  462.         $containerConfig \Pimcore::getContainer()->getParameter('pimcore.config');
  463.         $config $containerConfig['perspectives']['definitions'];
  464.         if (method_exists(\Pimcore\Config\LocationAwareConfigRepository::class, 'getStorageConfigurationCompatibilityLayer')) {
  465.             $storageConfig \Pimcore\Config\LocationAwareConfigRepository::getStorageConfigurationCompatibilityLayer(
  466.                 $containerConfig,
  467.                 'perspectives',
  468.                 'PIMCORE_CONFIG_STORAGE_DIR_PERSPECTIVES',
  469.                 'PIMCORE_WRITE_TARGET_PERSPECTIVES'
  470.             );
  471.         } else {
  472.             $storageConfig $containerConfig['config_location']['perspectives'] ?? null;
  473.         }
  474.         if (empty($storageConfig['write_target']['options']['directory'])) {
  475.             $storageConfig['write_target']['options']['directory'] = PIMCORE_CONFIGURATION_DIRECTORY.'/perspectives';
  476.         }
  477.         try {
  478.             $repository = new LocationAwareConfigRepository(
  479.                 $config,
  480.                 'pimcore_perspectives',
  481.                 $storageConfig
  482.             );
  483.         } catch (\Throwable $e) {
  484.             $repository = new LocationAwareConfigRepository(
  485.                 $config,
  486.                 'pimcore_perspectives',
  487.                 $storageConfig['write_target']['options']['directory'],
  488.                 null
  489.             );
  490.         }
  491.         foreach ($data as $key => $value) {
  492.             list($configKey$dataSource) = $repository->loadConfigByKey($key);
  493.             if ($repository->isWriteable($key$dataSource) === true) {
  494.                 unset($value['writeable']);
  495.                 $repository->saveConfig($key$value, function ($key$data) {
  496.                     return [
  497.                         'pimcore' => [
  498.                             'perspectives' => [
  499.                                 'definitions' => [
  500.                                     $key => $data,
  501.                                 ],
  502.                             ],
  503.                         ],
  504.                     ];
  505.                 });
  506.             }
  507.         }
  508.     }
  509.     private static function saveCustomView(array $data)
  510.     {
  511.         $containerConfig \Pimcore::getContainer()->getParameter('pimcore.config');
  512.         $config $containerConfig['custom_views']['definitions'];
  513.         if (method_exists(\Pimcore\Config\LocationAwareConfigRepository::class, 'getStorageConfigurationCompatibilityLayer')) {
  514.             $storageConfig \Pimcore\Config\LocationAwareConfigRepository::getStorageConfigurationCompatibilityLayer(
  515.                 $containerConfig,
  516.                 'custom_views',
  517.                 'PIMCORE_CONFIG_STORAGE_DIR_CUSTOM_VIEWS',
  518.                 'PIMCORE_WRITE_TARGET_CUSTOM_VIEWS'
  519.             );
  520.         } else {
  521.             $storageConfig $containerConfig['config_location']['custom_views'] ?? null;
  522.         }
  523.         if(empty($storageConfig['write_target']['options']['directory'])) {
  524.             $storageConfig['write_target']['options']['directory'] = PIMCORE_CONFIGURATION_DIRECTORY.'/custom-views';
  525.         }
  526.         try {
  527.             $repository = new LocationAwareConfigRepository(
  528.                 $config,
  529.                 'pimcore_custom_views',
  530.                 $storageConfig
  531.             );
  532.         } catch(\Throwable $e) {
  533.             $repository = new LocationAwareConfigRepository(
  534.                 $config,
  535.                 'pimcore_custom_views',
  536.                 $storageConfig['write_target']['options']['directory'],
  537.                 null
  538.             );
  539.         }
  540.         foreach ($data as $key => $value) {
  541.             $key = (string)$key;
  542.             list($configKey$dataSource) = $repository->loadConfigByKey($key);
  543.             if ($repository->isWriteable($key$dataSource)) {
  544.                 unset($value['writeable']);
  545.                 $repository->saveConfig($key$value, function ($key$data) {
  546.                     return [
  547.                         'pimcore' => [
  548.                             'custom_views' => [
  549.                                 'definitions' => [
  550.                                     $key => $data,
  551.                                 ],
  552.                             ],
  553.                         ],
  554.                     ];
  555.                 });
  556.             }
  557.         }
  558.     }
  559. }