vendor/pimcore/pimcore/bundles/AdminBundle/Controller/Admin/DataObject/ClassController.php line 71

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Bundle\AdminBundle\Controller\Admin\DataObject;
  15. use Pimcore\Bundle\AdminBundle\Controller\AdminController;
  16. use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
  17. use Pimcore\Controller\KernelControllerEventInterface;
  18. use Pimcore\Db;
  19. use Pimcore\Event\AdminEvents;
  20. use Pimcore\Logger;
  21. use Pimcore\Model\Asset;
  22. use Pimcore\Model\DataObject;
  23. use Pimcore\Model\Document;
  24. use Pimcore\Model\Translation;
  25. use Pimcore\Tool\Session;
  26. use Symfony\Component\EventDispatcher\GenericEvent;
  27. use Symfony\Component\HttpFoundation\Request;
  28. use Symfony\Component\HttpFoundation\Response;
  29. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  30. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  31. use Symfony\Component\Routing\Annotation\Route;
  32. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  33. /**
  34.  * @Route("/class", name="pimcore_admin_dataobject_class_")
  35.  *
  36.  * @internal
  37.  */
  38. class ClassController extends AdminController implements KernelControllerEventInterface
  39. {
  40.     /**
  41.      * @Route("/get-document-types", name="getdocumenttypes", methods={"GET"})
  42.      *
  43.      * @param Request $request
  44.      *
  45.      * @return JsonResponse
  46.      */
  47.     public function getDocumentTypesAction(Request $request)
  48.     {
  49.         $documentTypes Document::getTypes();
  50.         $typeItems = [];
  51.         foreach ($documentTypes as $documentType) {
  52.             $typeItems[] = [
  53.                 'text' => $documentType,
  54.             ];
  55.         }
  56.         return $this->adminJson($typeItems);
  57.     }
  58.     /**
  59.      * @Route("/get-asset-types", name="getassettypes", methods={"GET"})
  60.      *
  61.      * @param Request $request
  62.      *
  63.      * @return JsonResponse
  64.      */
  65.     public function getAssetTypesAction(Request $request)
  66.     {
  67.         $assetTypes Asset::getTypes();
  68.         $typeItems = [];
  69.         foreach ($assetTypes as $assetType) {
  70.             $typeItems[] = [
  71.                 'text' => $assetType,
  72.             ];
  73.         }
  74.         return $this->adminJson($typeItems);
  75.     }
  76.     /**
  77.      * @Route("/get-tree", name="gettree", methods={"GET", "POST"})
  78.      *
  79.      * @param Request $request
  80.      *
  81.      * @return JsonResponse
  82.      */
  83.     public function getTreeAction(Request $request)
  84.     {
  85.         $defaultIcon '/bundles/pimcoreadmin/img/flat-color-icons/class.svg';
  86.         $classesList = new DataObject\ClassDefinition\Listing();
  87.         $classesList->setOrderKey('name');
  88.         $classesList->setOrder('asc');
  89.         $classes $classesList->load();
  90.         // filter classes
  91.         if ($request->get('createAllowed')) {
  92.             $tmpClasses = [];
  93.             foreach ($classes as $class) {
  94.                 if ($this->getAdminUser()->isAllowed($class->getId(), 'class')) {
  95.                     $tmpClasses[] = $class;
  96.                 }
  97.             }
  98.             $classes $tmpClasses;
  99.         }
  100.         $withId $request->get('withId');
  101.         $getClassConfig = function ($class) use ($defaultIcon$withId) {
  102.             $text $class->getname();
  103.             if ($withId) {
  104.                 $text .= ' (' $class->getId() . ')';
  105.             }
  106.             $hasBrickField false;
  107.             foreach ($class->getFieldDefinitions() as $fieldDefinition) {
  108.                 if ($fieldDefinition instanceof DataObject\ClassDefinition\Data\Objectbricks) {
  109.                     $hasBrickField true;
  110.                     break;
  111.                 }
  112.             }
  113.             return [
  114.                 'id' => $class->getId(),
  115.                 'text' => $text,
  116.                 'leaf' => true,
  117.                 'icon' => $class->getIcon() ? htmlspecialchars($class->getIcon()) : $defaultIcon,
  118.                 'cls' => 'pimcore_class_icon',
  119.                 'propertyVisibility' => $class->getPropertyVisibility(),
  120.                 'enableGridLocking' => $class->isEnableGridLocking(),
  121.                 'hasBrickField' => $hasBrickField,
  122.             ];
  123.         };
  124.         // build groups
  125.         $groups = [];
  126.         foreach ($classes as $class) {
  127.             $groupName null;
  128.             if ($class->getGroup()) {
  129.                 $type 'manual';
  130.                 $groupName $class->getGroup();
  131.             } else {
  132.                 $type 'auto';
  133.                 if (preg_match('@^([A-Za-z])([^A-Z]+)@'$class->getName(), $matches)) {
  134.                     $groupName $matches[0];
  135.                 }
  136.                 if (!$groupName) {
  137.                     // this is eg. the case when class name uses only capital letters
  138.                     $groupName $class->getName();
  139.                 }
  140.             }
  141.             $groupName Translation::getByKeyLocalized($groupNameTranslation::DOMAIN_ADMINtruetrue);
  142.             if (!isset($groups[$groupName])) {
  143.                 $groups[$groupName] = [
  144.                     'classes' => [],
  145.                     'type' => $type,
  146.                 ];
  147.             }
  148.             $groups[$groupName]['classes'][] = $class;
  149.         }
  150.         $treeNodes = [];
  151.         if (!empty($groups)) {
  152.             $types array_column($groups'type');
  153.             array_multisort($typesSORT_ASCarray_keys($groups), SORT_ASC$groups);
  154.         }
  155.         if (!$request->get('grouped')) {
  156.             // list output
  157.             foreach ($groups as $groupName => $groupData) {
  158.                 foreach ($groupData['classes'] as $class) {
  159.                     $node $getClassConfig($class);
  160.                     if (count($groupData['classes']) > || $groupData['type'] == 'manual') {
  161.                         $node['group'] = $groupName;
  162.                     }
  163.                     $treeNodes[] = $node;
  164.                 }
  165.             }
  166.         } else {
  167.             // create json output
  168.             foreach ($groups as $groupName => $groupData) {
  169.                 if (count($groupData['classes']) === && $groupData['type'] == 'auto') {
  170.                     // no group, only one child
  171.                     $node $getClassConfig($groupData['classes'][0]);
  172.                 } else {
  173.                     // group classes
  174.                     $node = [
  175.                         'id' => 'folder_' $groupName,
  176.                         'text' => $groupName,
  177.                         'leaf' => false,
  178.                         'expandable' => true,
  179.                         'allowChildren' => true,
  180.                         'iconCls' => 'pimcore_icon_folder',
  181.                         'children' => [],
  182.                     ];
  183.                     foreach ($groupData['classes'] as $class) {
  184.                         $node['children'][] = $getClassConfig($class);
  185.                     }
  186.                 }
  187.                 $treeNodes[] = $node;
  188.             }
  189.         }
  190.         return $this->adminJson($treeNodes);
  191.     }
  192.     /**
  193.      * @Route("/get", name="get", methods={"GET"})
  194.      *
  195.      * @param Request $request
  196.      *
  197.      * @return JsonResponse
  198.      */
  199.     public function getAction(Request $request)
  200.     {
  201.         $class DataObject\ClassDefinition::getById($request->get('id'));
  202.         if (!$class) {
  203.             throw $this->createNotFoundException();
  204.         }
  205.         $class->setFieldDefinitions([]);
  206.         $isWriteable $class->isWritable();
  207.         $class $class->getObjectVars();
  208.         $class['isWriteable'] = $isWriteable;
  209.         return $this->adminJson($class);
  210.     }
  211.     /**
  212.      * @Route("/get-custom-layout", name="getcustomlayout", methods={"GET"})
  213.      *
  214.      * @param Request $request
  215.      *
  216.      * @return JsonResponse
  217.      */
  218.     public function getCustomLayoutAction(Request $request)
  219.     {
  220.         $customLayout DataObject\ClassDefinition\CustomLayout::getById($request->get('id'));
  221.         if (!$customLayout) {
  222.             $brickLayoutSeparator strpos($request->get('id'), '.brick.');
  223.             if ($brickLayoutSeparator !== false) {
  224.                 $customLayout DataObject\ClassDefinition\CustomLayout::getById(substr($request->get('id'), 0$brickLayoutSeparator));
  225.                 if ($customLayout instanceof DataObject\ClassDefinition\CustomLayout) {
  226.                     $customLayout DataObject\ClassDefinition\CustomLayout::create(
  227.                         [
  228.                             'name' => $customLayout->getName().' '.substr($request->get('id'), $brickLayoutSeparator+strlen('.brick.')),
  229.                             'userOwner' => $this->getAdminUser()->getId(),
  230.                             'classId' => $customLayout->getClassId(),
  231.                         ]
  232.                     );
  233.                     $customLayout->setId($request->get('id'));
  234.                     $customLayout->save();
  235.                 }
  236.             }
  237.             if (!$customLayout) {
  238.                 throw $this->createNotFoundException();
  239.             }
  240.         }
  241.         $isWriteable $customLayout->isWritable();
  242.         $customLayout $customLayout->getObjectVars();
  243.         $customLayout['isWriteable'] = $isWriteable;
  244.         return $this->adminJson(['success' => true'data' => $customLayout]);
  245.     }
  246.     /**
  247.      * @Route("/add", name="add", methods={"POST"})
  248.      *
  249.      * @param Request $request
  250.      *
  251.      * @return JsonResponse
  252.      */
  253.     public function addAction(Request $request)
  254.     {
  255.         $className $request->get('className');
  256.         $className $this->correctClassname($className);
  257.         $classId $request->get('classIdentifier');
  258.         $existingClass DataObject\ClassDefinition::getById($classId);
  259.         if ($existingClass) {
  260.             throw new \Exception('Class identifier already exists');
  261.         }
  262.         $class DataObject\ClassDefinition::create(
  263.             ['name' => $className,
  264.                 'userOwner' => $this->getAdminUser()->getId(), ]
  265.         );
  266.         $class->setId($classId);
  267.         $class->save(true);
  268.         return $this->adminJson(['success' => true'id' => $class->getId()]);
  269.     }
  270.     /**
  271.      * @Route("/add-custom-layout", name="addcustomlayout", methods={"POST"})
  272.      *
  273.      * @param Request $request
  274.      *
  275.      * @return JsonResponse
  276.      */
  277.     public function addCustomLayoutAction(Request $request)
  278.     {
  279.         $layoutId $request->get('layoutIdentifier');
  280.         $existingLayout DataObject\ClassDefinition\CustomLayout::getById($layoutId);
  281.         if ($existingLayout) {
  282.             throw new \Exception('Custom Layout identifier already exists');
  283.         }
  284.         $customLayout DataObject\ClassDefinition\CustomLayout::create(
  285.             [
  286.                 'name' => $request->get('layoutName'),
  287.                 'userOwner' => $this->getAdminUser()->getId(),
  288.                 'classId' => $request->get('classId'),
  289.             ]
  290.         );
  291.         $customLayout->setId($layoutId);
  292.         $customLayout->save();
  293.         $isWriteable $customLayout->isWritable();
  294.         $data $customLayout->getObjectVars();
  295.         $data['isWriteable'] = $isWriteable;
  296.         return $this->adminJson(['success' => true'id' => $customLayout->getId(), 'name' => $customLayout->getName(),
  297.                                  'data' => $data, ]);
  298.     }
  299.     /**
  300.      * @Route("/delete", name="delete", methods={"DELETE"})
  301.      *
  302.      * @param Request $request
  303.      *
  304.      * @return Response
  305.      */
  306.     public function deleteAction(Request $request)
  307.     {
  308.         $class DataObject\ClassDefinition::getById($request->get('id'));
  309.         if ($class) {
  310.             $class->delete();
  311.         }
  312.         return new Response();
  313.     }
  314.     /**
  315.      * @Route("/delete-custom-layout", name="deletecustomlayout", methods={"DELETE"})
  316.      *
  317.      * @param Request $request
  318.      *
  319.      * @return JsonResponse
  320.      */
  321.     public function deleteCustomLayoutAction(Request $request)
  322.     {
  323.         $customLayouts = new DataObject\ClassDefinition\CustomLayout\Listing();
  324.         $id $request->get('id');
  325.         $customLayouts->setFilter(function (DataObject\ClassDefinition\CustomLayout $layout) use ($id) {
  326.             $currentLayoutId $layout->getId();
  327.             return $currentLayoutId === $id || str_starts_with($currentLayoutId$id '.brick.');
  328.         });
  329.         foreach ($customLayouts->getLayoutDefinitions() as $customLayout) {
  330.             $customLayout->delete();
  331.         }
  332.         return $this->adminJson(['success' => true]);
  333.     }
  334.     /**
  335.      * @Route("/save-custom-layout", name="savecustomlayout", methods={"PUT"})
  336.      *
  337.      * @param Request $request
  338.      *
  339.      * @return JsonResponse
  340.      */
  341.     public function saveCustomLayoutAction(Request $request)
  342.     {
  343.         $customLayout DataObject\ClassDefinition\CustomLayout::getById($request->get('id'));
  344.         if (!$customLayout) {
  345.             throw $this->createNotFoundException();
  346.         }
  347.         $configuration $this->decodeJson($request->get('configuration'));
  348.         $values $this->decodeJson($request->get('values'));
  349.         $modificationDate = (int)$values['modificationDate'];
  350.         if ($modificationDate $customLayout->getModificationDate()) {
  351.             return $this->adminJson(['success' => false'msg' => 'custom_layout_changed']);
  352.         }
  353.         $configuration['datatype'] = 'layout';
  354.         $configuration['fieldtype'] = 'panel';
  355.         $configuration['name'] = 'pimcore_root';
  356.         try {
  357.             $layout DataObject\ClassDefinition\Service::generateLayoutTreeFromArray($configurationtrue);
  358.             $customLayout->setLayoutDefinitions($layout);
  359.             $customLayout->setName($values['name']);
  360.             $customLayout->setDescription($values['description']);
  361.             $customLayout->setDefault($values['default']);
  362.             $customLayout->save();
  363.             return $this->adminJson(['success' => true'id' => $customLayout->getId(), 'data' => $customLayout->getObjectVars()]);
  364.         } catch (\Exception $e) {
  365.             Logger::error($e->getMessage());
  366.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  367.         }
  368.     }
  369.     /**
  370.      * @Route("/save", name="save", methods={"PUT"})
  371.      *
  372.      * @param Request $request
  373.      *
  374.      * @return JsonResponse
  375.      *
  376.      * @throws \Exception
  377.      */
  378.     public function saveAction(Request $request)
  379.     {
  380.         $class DataObject\ClassDefinition::getById($request->get('id'));
  381.         if (!$class) {
  382.             throw $this->createNotFoundException();
  383.         }
  384.         $configuration $this->decodeJson($request->get('configuration'));
  385.         $values $this->decodeJson($request->get('values'));
  386.         // check if the class was changed during editing in the frontend
  387.         if ($class->getModificationDate() != $values['modificationDate']) {
  388.             throw new \Exception('The class was modified during editing, please reload the class and make your changes again');
  389.         }
  390.         if ($values['name'] != $class->getName()) {
  391.             $classByName DataObject\ClassDefinition::getByName($values['name']);
  392.             if ($classByName && $classByName->getId() != $class->getId()) {
  393.                 throw new \Exception('Class name already exists');
  394.             }
  395.             $values['name'] = $this->correctClassname($values['name']);
  396.             $class->rename($values['name']);
  397.         }
  398.         unset($values['creationDate']);
  399.         unset($values['userOwner']);
  400.         unset($values['layoutDefinitions']);
  401.         unset($values['fieldDefinitions']);
  402.         $configuration['datatype'] = 'layout';
  403.         $configuration['fieldtype'] = 'panel';
  404.         $configuration['name'] = 'pimcore_root';
  405.         $class->setValues($values);
  406.         try {
  407.             $layout DataObject\ClassDefinition\Service::generateLayoutTreeFromArray($configurationtrue);
  408.             $class->setLayoutDefinitions($layout);
  409.             $class->setUserModification($this->getAdminUser()->getId());
  410.             $class->setModificationDate(time());
  411.             $propertyVisibility = [];
  412.             foreach ($values as $key => $value) {
  413.                 if (preg_match('/propertyVisibility/i'$key)) {
  414.                     if (preg_match("/\.grid\./i"$key)) {
  415.                         $propertyVisibility['grid'][preg_replace("/propertyVisibility\.grid\./i"''$key)] = (bool) $value;
  416.                     } elseif (preg_match("/\.search\./i"$key)) {
  417.                         $propertyVisibility['search'][preg_replace("/propertyVisibility\.search\./i"''$key)] = (bool) $value;
  418.                     }
  419.                 }
  420.             }
  421.             if (!empty($propertyVisibility)) {
  422.                 $class->setPropertyVisibility($propertyVisibility);
  423.             }
  424.             $class->save();
  425.             // set the fielddefinitions to [] because we don't need them in the response
  426.             $class->setFieldDefinitions([]);
  427.             return $this->adminJson(['success' => true'class' => $class]);
  428.         } catch (\Exception $e) {
  429.             Logger::error($e->getMessage());
  430.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  431.         }
  432.     }
  433.     /**
  434.      * @param string $name
  435.      *
  436.      * @return string
  437.      */
  438.     protected function correctClassname($name)
  439.     {
  440.         $name preg_replace('/[^a-zA-Z0-9_]+/'''$name);
  441.         $name preg_replace('/^[0-9]+/'''$name);
  442.         return $name;
  443.     }
  444.     /**
  445.      * @Route("/import-class", name="importclass", methods={"POST", "PUT"})
  446.      *
  447.      * @param Request $request
  448.      *
  449.      * @return Response
  450.      */
  451.     public function importClassAction(Request $request)
  452.     {
  453.         $class DataObject\ClassDefinition::getById($request->get('id'));
  454.         if (!$class) {
  455.             throw $this->createNotFoundException();
  456.         }
  457.         $json file_get_contents($_FILES['Filedata']['tmp_name']);
  458.         $success DataObject\ClassDefinition\Service::importClassDefinitionFromJson($class$jsonfalsetrue);
  459.         $response $this->adminJson([
  460.             'success' => $success,
  461.         ]);
  462.         // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  463.         // Ext.form.Action.Submit and mark the submission as failed
  464.         $response->headers->set('Content-Type''text/html');
  465.         return $response;
  466.     }
  467.     /**
  468.      * @Route("/import-custom-layout-definition", name="importcustomlayoutdefinition", methods={"POST", "PUT"})
  469.      *
  470.      * @param Request $request
  471.      *
  472.      * @return Response
  473.      */
  474.     public function importCustomLayoutDefinitionAction(Request $request)
  475.     {
  476.         $success false;
  477.         $responseContent = [];
  478.         $json file_get_contents($_FILES['Filedata']['tmp_name']);
  479.         $importData $this->decodeJson($json);
  480.         $existingLayout null;
  481.         if (isset($importData['name'])) {
  482.             $existingLayout DataObject\ClassDefinition\CustomLayout::getByName($importData['name']);
  483.             if ($existingLayout instanceof DataObject\ClassDefinition\CustomLayout) {
  484.                 $responseContent['nameAlreadyInUse'] = true;
  485.             }
  486.         }
  487.         if (!$existingLayout instanceof DataObject\ClassDefinition\CustomLayout) {
  488.             $customLayoutId $request->get('id');
  489.             $customLayout DataObject\ClassDefinition\CustomLayout::getById($customLayoutId);
  490.             if ($customLayout) {
  491.                 try {
  492.                     $layout DataObject\ClassDefinition\Service::generateLayoutTreeFromArray($importData['layoutDefinitions'], true);
  493.                     $customLayout->setLayoutDefinitions($layout);
  494.                     if (isset($importData['name']) === true) {
  495.                         $customLayout->setName($importData['name']);
  496.                     }
  497.                     $customLayout->setDescription($importData['description']);
  498.                     $customLayout->save();
  499.                     $success true;
  500.                 } catch (\Exception $e) {
  501.                     Logger::error($e->getMessage());
  502.                 }
  503.             }
  504.             $responseContent['success'] = $success;
  505.         }
  506.         $response $this->adminJson($responseContent);
  507.         // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  508.         // Ext.form.Action.Submit and mark the submission as failed
  509.         $response->headers->set('Content-Type''text/html');
  510.         return $response;
  511.     }
  512.     /**
  513.      * @Route("/get-custom-layout-definitions", name="getcustomlayoutdefinitions", methods={"GET"})
  514.      *
  515.      * @param Request $request
  516.      *
  517.      * @return JsonResponse
  518.      */
  519.     public function getCustomLayoutDefinitionsAction(Request $request)
  520.     {
  521.         $classIds explode(','$request->get('classId'));
  522.         $list = new DataObject\ClassDefinition\CustomLayout\Listing();
  523.         $list->setFilter(function (DataObject\ClassDefinition\CustomLayout $layout) use ($classIds) {
  524.             return in_array($layout->getClassId(), $classIds) && !str_contains($layout->getId(), '.brick.');
  525.         });
  526.         $list $list->load();
  527.         $result = [];
  528.         foreach ($list as $item) {
  529.             $result[] = [
  530.                 'id' => $item->getId(),
  531.                 'name' => $item->getName() . ' (ID: ' $item->getId() . ')',
  532.                 'default' => $item->getDefault() ?: 0,
  533.             ];
  534.         }
  535.         return $this->adminJson(['success' => true'data' => $result]);
  536.     }
  537.     /**
  538.      * @Route("/get-all-layouts", name="getalllayouts", methods={"GET"})
  539.      *
  540.      * @param Request $request
  541.      *
  542.      * @return JsonResponse
  543.      */
  544.     public function getAllLayoutsAction(Request $request)
  545.     {
  546.         // get all classes
  547.         $resultList = [];
  548.         $mapping = [];
  549.         $customLayouts = new DataObject\ClassDefinition\CustomLayout\Listing();
  550.         $customLayouts->setFilter(function (DataObject\ClassDefinition\CustomLayout $layout) {
  551.             return !str_contains($layout->getId(), '.brick.');
  552.         });
  553.         $customLayouts->setOrder(function (DataObject\ClassDefinition\CustomLayout $aDataObject\ClassDefinition\CustomLayout $b) {
  554.             return strcmp($a->getName(), $b->getName());
  555.         });
  556.         $customLayouts $customLayouts->load();
  557.         foreach ($customLayouts as $layout) {
  558.             $mapping[$layout->getClassId()][] = $layout;
  559.         }
  560.         $classList = new DataObject\ClassDefinition\Listing();
  561.         $classList->setOrder('ASC');
  562.         $classList->setOrderKey('name');
  563.         $classList $classList->load();
  564.         foreach ($classList as $class) {
  565.             if (isset($mapping[$class->getId()])) {
  566.                 $classMapping $mapping[$class->getId()];
  567.                 $resultList[] = [
  568.                     'type' => 'master',
  569.                     'id' => $class->getId() . '_' 0,
  570.                     'name' => $class->getName(),
  571.                 ];
  572.                 foreach ($classMapping as $layout) {
  573.                     $resultList[] = [
  574.                         'type' => 'custom',
  575.                         'id' => $class->getId() . '_' $layout->getId(),
  576.                         'name' => $class->getName() . ' - ' $layout->getName(),
  577.                     ];
  578.                 }
  579.             }
  580.         }
  581.         return $this->adminJson(['data' => $resultList]);
  582.     }
  583.     /**
  584.      * @Route("/export-class", name="exportclass", methods={"GET"})
  585.      *
  586.      * @param Request $request
  587.      *
  588.      * @return Response
  589.      */
  590.     public function exportClassAction(Request $request)
  591.     {
  592.         $id $request->get('id');
  593.         $class DataObject\ClassDefinition::getById($id);
  594.         if (!$class instanceof DataObject\ClassDefinition) {
  595.             $errorMessage ': Class with id [ ' $id ' not found. ]';
  596.             Logger::error($errorMessage);
  597.             throw $this->createNotFoundException($errorMessage);
  598.         }
  599.         $json DataObject\ClassDefinition\Service::generateClassDefinitionJson($class);
  600.         $response = new Response($json);
  601.         $response->headers->set('Content-type''application/json');
  602.         $response->headers->set('Content-Disposition''attachment; filename="class_' $class->getName() . '_export.json"');
  603.         return $response;
  604.     }
  605.     /**
  606.      * @Route("/export-custom-layout-definition", name="exportcustomlayoutdefinition", methods={"GET"})
  607.      *
  608.      * @param Request $request
  609.      *
  610.      * @return Response
  611.      */
  612.     public function exportCustomLayoutDefinitionAction(Request $request)
  613.     {
  614.         $id $request->get('id');
  615.         if ($id) {
  616.             $customLayout DataObject\ClassDefinition\CustomLayout::getById($id);
  617.             if ($customLayout) {
  618.                 $name $customLayout->getName();
  619.                 $json DataObject\ClassDefinition\Service::generateCustomLayoutJson($customLayout);
  620.                 $response = new Response($json);
  621.                 $response->headers->set('Content-type''application/json');
  622.                 $response->headers->set('Content-Disposition''attachment; filename="custom_definition_' $name '_export.json"');
  623.                 return $response;
  624.             }
  625.         }
  626.         $errorMessage ': Custom Layout with id [ ' $id ' not found. ]';
  627.         Logger::error($errorMessage);
  628.         throw $this->createNotFoundException($errorMessage);
  629.     }
  630.     /**
  631.      * FIELDCOLLECTIONS
  632.      */
  633.     /**
  634.      * @Route("/fieldcollection-get", name="fieldcollectionget", methods={"GET"})
  635.      *
  636.      * @param Request $request
  637.      *
  638.      * @return JsonResponse
  639.      */
  640.     public function fieldcollectionGetAction(Request $request)
  641.     {
  642.         $fc DataObject\Fieldcollection\Definition::getByKey($request->get('id'));
  643.         $isWriteable $fc->isWritable();
  644.         $fc $fc->getObjectVars();
  645.         $fc['isWriteable'] = $isWriteable;
  646.         return $this->adminJson($fc);
  647.     }
  648.     /**
  649.      * @Route("/fieldcollection-update", name="fieldcollectionupdate", methods={"PUT", "POST"})
  650.      *
  651.      * @param Request $request
  652.      *
  653.      * @return JsonResponse
  654.      */
  655.     public function fieldcollectionUpdateAction(Request $request)
  656.     {
  657.         try {
  658.             $key $request->get('key');
  659.             $title $request->get('title');
  660.             $group $request->get('group');
  661.             if ($request->get('task') == 'add') {
  662.                 // check for existing fieldcollection with same name with different lower/upper cases
  663.                 $list = new DataObject\Fieldcollection\Definition\Listing();
  664.                 $list $list->load();
  665.                 foreach ($list as $item) {
  666.                     if (strtolower($key) === strtolower($item->getKey())) {
  667.                         throw new \Exception('FieldCollection with the same name already exists (lower/upper cases may be different)');
  668.                     }
  669.                 }
  670.             }
  671.             $fcDef = new DataObject\Fieldcollection\Definition();
  672.             $fcDef->setKey($key);
  673.             $fcDef->setTitle($title);
  674.             $fcDef->setGroup($group);
  675.             if ($request->get('values')) {
  676.                 $values $this->decodeJson($request->get('values'));
  677.                 $fcDef->setParentClass($values['parentClass']);
  678.                 $fcDef->setImplementsInterfaces($values['implementsInterfaces']);
  679.                 $fcDef->setGenerateTypeDeclarations($values['generateTypeDeclarations']);
  680.             }
  681.             if ($request->get('configuration')) {
  682.                 $configuration $this->decodeJson($request->get('configuration'));
  683.                 $configuration['datatype'] = 'layout';
  684.                 $configuration['fieldtype'] = 'panel';
  685.                 $layout DataObject\ClassDefinition\Service::generateLayoutTreeFromArray($configurationtrue);
  686.                 $fcDef->setLayoutDefinitions($layout);
  687.             }
  688.             $fcDef->save();
  689.             return $this->adminJson(['success' => true'id' => $fcDef->getKey()]);
  690.         } catch (\Exception $e) {
  691.             Logger::error($e->getMessage());
  692.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  693.         }
  694.     }
  695.     /**
  696.      * @Route("/import-fieldcollection", name="importfieldcollection", methods={"POST"})
  697.      *
  698.      * @param Request $request
  699.      *
  700.      * @return Response
  701.      */
  702.     public function importFieldcollectionAction(Request $request)
  703.     {
  704.         $fieldCollection DataObject\Fieldcollection\Definition::getByKey($request->get('id'));
  705.         $data file_get_contents($_FILES['Filedata']['tmp_name']);
  706.         $success DataObject\ClassDefinition\Service::importFieldCollectionFromJson($fieldCollection$data);
  707.         $response $this->adminJson([
  708.             'success' => $success,
  709.         ]);
  710.         // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  711.         // Ext.form.Action.Submit and mark the submission as failed
  712.         $response->headers->set('Content-Type''text/html');
  713.         return $response;
  714.     }
  715.     /**
  716.      * @Route("/export-fieldcollection", name="exportfieldcollection", methods={"GET"})
  717.      *
  718.      * @param Request $request
  719.      *
  720.      * @return Response
  721.      */
  722.     public function exportFieldcollectionAction(Request $request)
  723.     {
  724.         $fieldCollection DataObject\Fieldcollection\Definition::getByKey($request->get('id'));
  725.         if (!$fieldCollection instanceof DataObject\Fieldcollection\Definition) {
  726.             $errorMessage ': Field-Collection with id [ ' $request->get('id') . ' not found. ]';
  727.             Logger::error($errorMessage);
  728.             throw $this->createNotFoundException($errorMessage);
  729.         }
  730.         $json DataObject\ClassDefinition\Service::generateFieldCollectionJson($fieldCollection);
  731.         $response = new Response($json);
  732.         $response->headers->set('Content-type''application/json');
  733.         $response->headers->set('Content-Disposition''attachment; filename="fieldcollection_' $fieldCollection->getKey() . '_export.json"');
  734.         return $response;
  735.     }
  736.     /**
  737.      * @Route("/fieldcollection-delete", name="fieldcollectiondelete", methods={"DELETE"})
  738.      *
  739.      * @param Request $request
  740.      *
  741.      * @return JsonResponse
  742.      */
  743.     public function fieldcollectionDeleteAction(Request $request)
  744.     {
  745.         $fc DataObject\Fieldcollection\Definition::getByKey($request->get('id'));
  746.         $fc->delete();
  747.         return $this->adminJson(['success' => true]);
  748.     }
  749.     /**
  750.      * @Route("/fieldcollection-tree", name="fieldcollectiontree", methods={"GET", "POST"})
  751.      *
  752.      * @param Request $request
  753.      * @param EventDispatcherInterface $eventDispatcher
  754.      *
  755.      * @return JsonResponse
  756.      */
  757.     public function fieldcollectionTreeAction(Request $requestEventDispatcherInterface $eventDispatcher)
  758.     {
  759.         $list = new DataObject\Fieldcollection\Definition\Listing();
  760.         $list $list->load();
  761.         $forObjectEditor $request->get('forObjectEditor');
  762.         $layoutDefinitions = [];
  763.         $definitions = [];
  764.         $allowedTypes null;
  765.         if ($request->query->has('allowedTypes')) {
  766.             $allowedTypes explode(','$request->get('allowedTypes'));
  767.         }
  768.         $object DataObject\Concrete::getById((int) $request->get('object_id'));
  769.         $currentLayoutId $request->get('layoutId'null);
  770.         $user \Pimcore\Tool\Admin::getCurrentUser();
  771.         $groups = [];
  772.         foreach ($list as $item) {
  773.             if ($allowedTypes && !in_array($item->getKey(), $allowedTypes)) {
  774.                 continue;
  775.             }
  776.             if ($item->getGroup()) {
  777.                 if (!isset($groups[$item->getGroup()])) {
  778.                     $groups[$item->getGroup()] = [
  779.                         'id' => 'group_' $item->getKey(),
  780.                         'text' => htmlspecialchars($item->getGroup()),
  781.                         'expandable' => true,
  782.                         'leaf' => false,
  783.                         'allowChildren' => true,
  784.                         'iconCls' => 'pimcore_icon_folder',
  785.                         'group' => $item->getGroup(),
  786.                         'children' => [],
  787.                     ];
  788.                 }
  789.                 if ($forObjectEditor) {
  790.                     $itemLayoutDefinitions $item->getLayoutDefinitions();
  791.                     DataObject\Service::enrichLayoutDefinition($itemLayoutDefinitions$object);
  792.                     if ($currentLayoutId == -&& $user->isAdmin()) {
  793.                         DataObject\Service::createSuperLayout($itemLayoutDefinitions);
  794.                     }
  795.                     $layoutDefinitions[$item->getKey()] = $itemLayoutDefinitions;
  796.                 }
  797.                 $groups[$item->getGroup()]['children'][] =
  798.                     [
  799.                         'id' => $item->getKey(),
  800.                         'text' => $item->getKey(),
  801.                         'title' => $item->getTitle(),
  802.                         'key' => $item->getKey(),
  803.                         'leaf' => true,
  804.                         'iconCls' => 'pimcore_icon_fieldcollection',
  805.                     ];
  806.             } else {
  807.                 if ($forObjectEditor) {
  808.                     $itemLayoutDefinitions $item->getLayoutDefinitions();
  809.                     DataObject\Service::enrichLayoutDefinition($itemLayoutDefinitions$object);
  810.                     if ($currentLayoutId == -&& $user->isAdmin()) {
  811.                         DataObject\Service::createSuperLayout($itemLayoutDefinitions);
  812.                     }
  813.                     $layoutDefinitions[$item->getKey()] = $itemLayoutDefinitions;
  814.                 }
  815.                 $definitions[] = [
  816.                     'id' => $item->getKey(),
  817.                     'text' => $item->getKey(),
  818.                     'title' => $item->getTitle(),
  819.                     'key' => $item->getKey(),
  820.                     'leaf' => true,
  821.                     'iconCls' => 'pimcore_icon_fieldcollection',
  822.                 ];
  823.             }
  824.         }
  825.         foreach ($groups as $group) {
  826.             $definitions[] = $group;
  827.         }
  828.         $event = new GenericEvent($this, [
  829.             'list' => $definitions,
  830.             'objectId' => $request->get('object_id'),
  831.             'layoutDefinitions' => $layoutDefinitions,
  832.         ]);
  833.         $eventDispatcher->dispatch($eventAdminEvents::CLASS_FIELDCOLLECTION_LIST_PRE_SEND_DATA);
  834.         $definitions $event->getArgument('list');
  835.         $layoutDefinitions $event->getArgument('layoutDefinitions');
  836.         if ($forObjectEditor) {
  837.             return $this->adminJson(['fieldcollections' => $definitions'layoutDefinitions' => $layoutDefinitions]);
  838.         }
  839.         return $this->adminJson($definitions);
  840.     }
  841.     /**
  842.      * @Route("/fieldcollection-list", name="fieldcollectionlist", methods={"GET"})
  843.      *
  844.      * @param Request $request
  845.      * @param EventDispatcherInterface $eventDispatcher
  846.      *
  847.      * @return JsonResponse
  848.      */
  849.     public function fieldcollectionListAction(Request $requestEventDispatcherInterface $eventDispatcher)
  850.     {
  851.         $user \Pimcore\Tool\Admin::getCurrentUser();
  852.         $currentLayoutId $request->get('layoutId');
  853.         $list = new DataObject\Fieldcollection\Definition\Listing();
  854.         $list $list->load();
  855.         if ($request->query->has('allowedTypes')) {
  856.             $filteredList = [];
  857.             $allowedTypes explode(','$request->get('allowedTypes'));
  858.             foreach ($list as $type) {
  859.                 if (in_array($type->getKey(), $allowedTypes)) {
  860.                     $filteredList[] = $type;
  861.                     // mainly for objects-meta data-type
  862.                     $layoutDefinitions $type->getLayoutDefinitions();
  863.                     $context = [
  864.                         'containerType' => 'fieldcollection',
  865.                         'containerKey' => $type->getKey(),
  866.                         'outerFieldname' => $request->get('field_name'),
  867.                     ];
  868.                     $object DataObject\Concrete::getById((int) $request->get('object_id'));
  869.                     DataObject\Service::enrichLayoutDefinition($layoutDefinitions$object$context);
  870.                     if ($currentLayoutId == -&& $user->isAdmin()) {
  871.                         DataObject\Service::createSuperLayout($layoutDefinitions);
  872.                     }
  873.                 }
  874.             }
  875.             $list $filteredList;
  876.         }
  877.         $event = new GenericEvent($this, [
  878.             'list' => $list,
  879.             'objectId' => $request->get('object_id'),
  880.         ]);
  881.         $eventDispatcher->dispatch($eventAdminEvents::CLASS_FIELDCOLLECTION_LIST_PRE_SEND_DATA);
  882.         $list $event->getArgument('list');
  883.         return $this->adminJson(['fieldcollections' => $list]);
  884.     }
  885.     /**
  886.      * @Route("/get-class-definition-for-column-config", name="getclassdefinitionforcolumnconfig", methods={"GET"})
  887.      *
  888.      * @param Request $request
  889.      *
  890.      * @return JsonResponse
  891.      */
  892.     public function getClassDefinitionForColumnConfigAction(Request $request)
  893.     {
  894.         $class DataObject\ClassDefinition::getById($request->get('id'));
  895.         if (!$class) {
  896.             throw $this->createNotFoundException();
  897.         }
  898.         $objectId = (int)$request->get('oid');
  899.         $filteredDefinitions DataObject\Service::getCustomLayoutDefinitionForGridColumnConfig($class$objectId);
  900.         /** @var DataObject\ClassDefinition\Layout $layoutDefinitions */
  901.         $layoutDefinitions = isset($filteredDefinitions['layoutDefinition']) ? $filteredDefinitions['layoutDefinition'] : false;
  902.         $filteredFieldDefinition = isset($filteredDefinitions['fieldDefinition']) ? $filteredDefinitions['fieldDefinition'] : false;
  903.         $class->setFieldDefinitions([]);
  904.         $result = [];
  905.         DataObject\Service::enrichLayoutDefinition($layoutDefinitions);
  906.         $result['objectColumns']['children'] = $layoutDefinitions->getChildren();
  907.         $result['objectColumns']['nodeLabel'] = 'object_columns';
  908.         $result['objectColumns']['nodeType'] = 'object';
  909.         // array("id", "fullpath", "published", "creationDate", "modificationDate", "filename", "classname");
  910.         $systemColumnNames DataObject\Concrete::SYSTEM_COLUMN_NAMES;
  911.         $systemColumns = [];
  912.         foreach ($systemColumnNames as $systemColumn) {
  913.             $systemColumns[] = ['title' => $systemColumn'name' => $systemColumn'datatype' => 'data''fieldtype' => 'system'];
  914.         }
  915.         $result['systemColumns']['nodeLabel'] = 'system_columns';
  916.         $result['systemColumns']['nodeType'] = 'system';
  917.         $result['systemColumns']['children'] = $systemColumns;
  918.         $list = new DataObject\Objectbrick\Definition\Listing();
  919.         $list $list->load();
  920.         foreach ($list as $brickDefinition) {
  921.             $classDefs $brickDefinition->getClassDefinitions();
  922.             if (!empty($classDefs)) {
  923.                 foreach ($classDefs as $classDef) {
  924.                     if ($classDef['classname'] == $class->getName()) {
  925.                         $fieldName $classDef['fieldname'];
  926.                         if ($filteredFieldDefinition && !$filteredFieldDefinition[$fieldName]) {
  927.                             continue;
  928.                         }
  929.                         $key $brickDefinition->getKey();
  930.                         $brickLayoutDefinitions $brickDefinition->getLayoutDefinitions();
  931.                         $context = [
  932.                             'containerType' => 'objectbrick',
  933.                             'containerKey' => $key,
  934.                             'outerFieldname' => $fieldName,
  935.                         ];
  936.                         DataObject\Service::enrichLayoutDefinition($brickLayoutDefinitionsnull$context);
  937.                         $result[$key]['nodeLabel'] = $key;
  938.                         $result[$key]['brickField'] = $fieldName;
  939.                         $result[$key]['nodeType'] = 'objectbricks';
  940.                         $result[$key]['children'] = $brickLayoutDefinitions->getChildren();
  941.                         break;
  942.                     }
  943.                 }
  944.             }
  945.         }
  946.         return $this->adminJson($result);
  947.     }
  948.     /**
  949.      * OBJECT BRICKS
  950.      */
  951.     /**
  952.      * @Route("/objectbrick-get", name="objectbrickget", methods={"GET"})
  953.      *
  954.      * @param Request $request
  955.      *
  956.      * @return JsonResponse
  957.      */
  958.     public function objectbrickGetAction(Request $request)
  959.     {
  960.         $fc DataObject\Objectbrick\Definition::getByKey($request->get('id'));
  961.         $isWriteable $fc->isWritable();
  962.         $fc $fc->getObjectVars();
  963.         $fc['isWriteable'] = $isWriteable;
  964.         return $this->adminJson($fc);
  965.     }
  966.     /**
  967.      * @Route("/objectbrick-update", name="objectbrickupdate", methods={"PUT", "POST"})
  968.      *
  969.      * @param Request $request
  970.      * @param EventDispatcherInterface $eventDispatcher
  971.      *
  972.      * @return JsonResponse
  973.      */
  974.     public function objectbrickUpdateAction(Request $requestEventDispatcherInterface $eventDispatcher)
  975.     {
  976.         try {
  977.             $key $request->get('key');
  978.             $title $request->get('title');
  979.             $group $request->get('group');
  980.             if ($request->get('task') == 'add') {
  981.                 // check for existing brick with same name with different lower/upper cases
  982.                 $list = new DataObject\Objectbrick\Definition\Listing();
  983.                 $list $list->load();
  984.                 foreach ($list as $item) {
  985.                     if (strtolower($key) === strtolower($item->getKey())) {
  986.                         throw new \Exception('Brick with the same name already exists (lower/upper cases may be different)');
  987.                     }
  988.                 }
  989.             }
  990.             // now we create a new definition
  991.             $brickDef = new DataObject\Objectbrick\Definition();
  992.             $brickDef->setKey($key);
  993.             $brickDef->setTitle($title);
  994.             $brickDef->setGroup($group);
  995.             if ($request->get('values')) {
  996.                 $values $this->decodeJson($request->get('values'));
  997.                 $brickDef->setParentClass($values['parentClass']);
  998.                 $brickDef->setImplementsInterfaces($values['implementsInterfaces']);
  999.                 $brickDef->setClassDefinitions($values['classDefinitions']);
  1000.                 $brickDef->setGenerateTypeDeclarations($values['generateTypeDeclarations']);
  1001.             }
  1002.             if ($request->get('configuration')) {
  1003.                 $configuration $this->decodeJson($request->get('configuration'));
  1004.                 $configuration['datatype'] = 'layout';
  1005.                 $configuration['fieldtype'] = 'panel';
  1006.                 $layout DataObject\ClassDefinition\Service::generateLayoutTreeFromArray($configurationtrue);
  1007.                 $brickDef->setLayoutDefinitions($layout);
  1008.             }
  1009.             $event = new GenericEvent($this, [
  1010.                 'brickDefinition' => $brickDef,
  1011.             ]);
  1012.             $eventDispatcher->dispatch($eventAdminEvents::CLASS_OBJECTBRICK_UPDATE_DEFINITION);
  1013.             $brickDef $event->getArgument('brickDefinition');
  1014.             $brickDef->save();
  1015.             return $this->adminJson(['success' => true'id' => $brickDef->getKey()]);
  1016.         } catch (\Exception $e) {
  1017.             Logger::error($e->getMessage());
  1018.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  1019.         }
  1020.     }
  1021.     /**
  1022.      * @Route("/import-objectbrick", name="importobjectbrick", methods={"POST"})
  1023.      *
  1024.      * @param Request $request
  1025.      *
  1026.      * @return JsonResponse
  1027.      */
  1028.     public function importObjectbrickAction(Request $request)
  1029.     {
  1030.         $objectBrick DataObject\Objectbrick\Definition::getByKey($request->get('id'));
  1031.         $data file_get_contents($_FILES['Filedata']['tmp_name']);
  1032.         $success DataObject\ClassDefinition\Service::importObjectBrickFromJson($objectBrick$data);
  1033.         $response $this->adminJson([
  1034.             'success' => $success,
  1035.         ]);
  1036.         // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  1037.         // Ext.form.Action.Submit and mark the submission as failed
  1038.         $response->headers->set('Content-Type''text/html');
  1039.         return $response;
  1040.     }
  1041.     /**
  1042.      * @Route("/export-objectbrick", name="exportobjectbrick", methods={"GET"})
  1043.      *
  1044.      * @param Request $request
  1045.      *
  1046.      * @return Response
  1047.      */
  1048.     public function exportObjectbrickAction(Request $request)
  1049.     {
  1050.         $objectBrick DataObject\Objectbrick\Definition::getByKey($request->get('id'));
  1051.         if (!$objectBrick instanceof DataObject\Objectbrick\Definition) {
  1052.             $errorMessage ': Object-Brick with id [ ' $request->get('id') . ' not found. ]';
  1053.             Logger::error($errorMessage);
  1054.             throw $this->createNotFoundException($errorMessage);
  1055.         }
  1056.         $xml DataObject\ClassDefinition\Service::generateObjectBrickJson($objectBrick);
  1057.         $response = new Response($xml);
  1058.         $response->headers->set('Content-type''application/json');
  1059.         $response->headers->set('Content-Disposition''attachment; filename="objectbrick_' $objectBrick->getKey() . '_export.json"');
  1060.         return $response;
  1061.     }
  1062.     /**
  1063.      * @Route("/objectbrick-delete", name="objectbrickdelete", methods={"DELETE"})
  1064.      *
  1065.      * @param Request $request
  1066.      *
  1067.      * @return JsonResponse
  1068.      */
  1069.     public function objectbrickDeleteAction(Request $request)
  1070.     {
  1071.         $fc DataObject\Objectbrick\Definition::getByKey($request->get('id'));
  1072.         $fc->delete();
  1073.         return $this->adminJson(['success' => true]);
  1074.     }
  1075.     /**
  1076.      * @Route("/objectbrick-tree", name="objectbricktree", methods={"GET", "POST"})
  1077.      *
  1078.      * @param Request $request
  1079.      * @param EventDispatcherInterface $eventDispatcher
  1080.      *
  1081.      * @return JsonResponse
  1082.      */
  1083.     public function objectbrickTreeAction(Request $requestEventDispatcherInterface $eventDispatcher)
  1084.     {
  1085.         $list = new DataObject\Objectbrick\Definition\Listing();
  1086.         $list $list->load();
  1087.         $forObjectEditor $request->get('forObjectEditor');
  1088.         $context null;
  1089.         $layoutDefinitions = [];
  1090.         $groups = [];
  1091.         $definitions = [];
  1092.         $fieldname null;
  1093.         $className null;
  1094.         $object DataObject\Concrete::getById((int) $request->get('object_id'));
  1095.         if ($request->query->has('class_id') && $request->query->has('field_name')) {
  1096.             $classId $request->get('class_id');
  1097.             $fieldname $request->get('field_name');
  1098.             $classDefinition DataObject\ClassDefinition::getById($classId);
  1099.             $className $classDefinition->getName();
  1100.         }
  1101.         foreach ($list as $item) {
  1102.             if ($forObjectEditor) {
  1103.                 $context = [
  1104.                     'containerType' => 'objectbrick',
  1105.                     'containerKey' => $item->getKey(),
  1106.                     'outerFieldname' => $fieldname,
  1107.                 ];
  1108.             }
  1109.             if ($request->query->has('class_id') && $request->query->has('field_name')) {
  1110.                 $keep false;
  1111.                 $clsDefs $item->getClassDefinitions();
  1112.                 if (!empty($clsDefs)) {
  1113.                     foreach ($clsDefs as $cd) {
  1114.                         if ($cd['classname'] == $className && $cd['fieldname'] == $fieldname) {
  1115.                             $keep true;
  1116.                             continue;
  1117.                         }
  1118.                     }
  1119.                 }
  1120.                 if (!$keep) {
  1121.                     continue;
  1122.                 }
  1123.             }
  1124.             if ($item->getGroup()) {
  1125.                 if (!isset($groups[$item->getGroup()])) {
  1126.                     $groups[$item->getGroup()] = [
  1127.                         'id' => 'group_' $item->getKey(),
  1128.                         'text' => htmlspecialchars($item->getGroup()),
  1129.                         'expandable' => true,
  1130.                         'leaf' => false,
  1131.                         'allowChildren' => true,
  1132.                         'iconCls' => 'pimcore_icon_folder',
  1133.                         'group' => $item->getGroup(),
  1134.                         'children' => [],
  1135.                     ];
  1136.                 }
  1137.                 if ($forObjectEditor) {
  1138.                     $layoutId $request->get('layoutId');
  1139.                     $itemLayoutDefinitions null;
  1140.                     if ($layoutId) {
  1141.                         $layout DataObject\ClassDefinition\CustomLayout::getById($layoutId.'.brick.'.$item->getKey());
  1142.                         if ($layout instanceof DataObject\ClassDefinition\CustomLayout) {
  1143.                             $itemLayoutDefinitions $layout->getLayoutDefinitions();
  1144.                         }
  1145.                     }
  1146.                     if ($itemLayoutDefinitions === null) {
  1147.                         $itemLayoutDefinitions $item->getLayoutDefinitions();
  1148.                     }
  1149.                     DataObject\Service::enrichLayoutDefinition($itemLayoutDefinitions$object$context);
  1150.                     $layoutDefinitions[$item->getKey()] = $itemLayoutDefinitions;
  1151.                 }
  1152.                 $groups[$item->getGroup()]['children'][] =
  1153.                     [
  1154.                         'id' => $item->getKey(),
  1155.                         'text' => $item->getKey(),
  1156.                         'title' => $item->getTitle(),
  1157.                         'key' => $item->getKey(),
  1158.                         'leaf' => true,
  1159.                         'iconCls' => 'pimcore_icon_objectbricks',
  1160.                     ];
  1161.             } else {
  1162.                 if ($forObjectEditor) {
  1163.                     $layout $item->getLayoutDefinitions();
  1164.                     $currentLayoutId $request->get('layoutId'null);
  1165.                     $user $this->getAdminUser();
  1166.                     if ($currentLayoutId == -&& $user->isAdmin()) {
  1167.                         DataObject\Service::createSuperLayout($layout);
  1168.                     } elseif ($currentLayoutId) {
  1169.                         $customLayout DataObject\ClassDefinition\CustomLayout::getById($currentLayoutId.'.brick.'.$item->getKey());
  1170.                         if ($customLayout instanceof DataObject\ClassDefinition\CustomLayout) {
  1171.                             $layout $customLayout->getLayoutDefinitions();
  1172.                         }
  1173.                     }
  1174.                     DataObject\Service::enrichLayoutDefinition($layout$object$context);
  1175.                     $layoutDefinitions[$item->getKey()] = $layout;
  1176.                 }
  1177.                 $definitions[] = [
  1178.                     'id' => $item->getKey(),
  1179.                     'text' => $item->getKey(),
  1180.                     'title' => $item->getTitle(),
  1181.                     'key' => $item->getKey(),
  1182.                     'leaf' => true,
  1183.                     'iconCls' => 'pimcore_icon_objectbricks',
  1184.                 ];
  1185.             }
  1186.         }
  1187.         foreach ($groups as $group) {
  1188.             $definitions[] = $group;
  1189.         }
  1190.         $event = new GenericEvent($this, [
  1191.             'list' => $definitions,
  1192.             'objectId' => $request->get('object_id'),
  1193.         ]);
  1194.         $eventDispatcher->dispatch($eventAdminEvents::CLASS_OBJECTBRICK_LIST_PRE_SEND_DATA);
  1195.         $definitions $event->getArgument('list');
  1196.         if ($forObjectEditor) {
  1197.             return $this->adminJson(['objectbricks' => $definitions'layoutDefinitions' => $layoutDefinitions]);
  1198.         } else {
  1199.             return $this->adminJson($definitions);
  1200.         }
  1201.     }
  1202.     /**
  1203.      * @Route("/objectbrick-list", name="objectbricklist", methods={"GET"})
  1204.      *
  1205.      * @param Request $request
  1206.      * @param EventDispatcherInterface $eventDispatcher
  1207.      *
  1208.      * @return JsonResponse
  1209.      */
  1210.     public function objectbrickListAction(Request $requestEventDispatcherInterface $eventDispatcher)
  1211.     {
  1212.         $list = new DataObject\Objectbrick\Definition\Listing();
  1213.         $list $list->load();
  1214.         if ($request->query->has('class_id') && $request->query->has('field_name')) {
  1215.             $filteredList = [];
  1216.             $classId $request->get('class_id');
  1217.             $fieldname $request->get('field_name');
  1218.             $classDefinition DataObject\ClassDefinition::getById($classId);
  1219.             $className $classDefinition->getName();
  1220.             foreach ($list as $type) {
  1221.                 $clsDefs $type->getClassDefinitions();
  1222.                 if (!empty($clsDefs)) {
  1223.                     foreach ($clsDefs as $cd) {
  1224.                         if ($cd['classname'] == $className && $cd['fieldname'] == $fieldname) {
  1225.                             $filteredList[] = $type;
  1226.                             continue;
  1227.                         }
  1228.                     }
  1229.                 }
  1230.                 $layout $type->getLayoutDefinitions();
  1231.                 $currentLayoutId $request->get('layoutId'null);
  1232.                 $user $this->getAdminUser();
  1233.                 if ($currentLayoutId == -&& $user->isAdmin()) {
  1234.                     DataObject\Service::createSuperLayout($layout);
  1235.                     $objectData['layout'] = $layout;
  1236.                 }
  1237.                 $context = [
  1238.                     'containerType' => 'objectbrick',
  1239.                     'containerKey' => $type->getKey(),
  1240.                     'outerFieldname' => $request->get('field_name'),
  1241.                 ];
  1242.                 $object DataObject\Concrete::getById((int) $request->get('object_id'));
  1243.                 DataObject\Service::enrichLayoutDefinition($layout$object$context);
  1244.                 $type->setLayoutDefinitions($layout);
  1245.             }
  1246.             $list $filteredList;
  1247.         }
  1248.         $event = new GenericEvent($this, [
  1249.             'list' => $list,
  1250.             'objectId' => $request->get('object_id'),
  1251.         ]);
  1252.         $eventDispatcher->dispatch($eventAdminEvents::CLASS_OBJECTBRICK_LIST_PRE_SEND_DATA);
  1253.         $list $event->getArgument('list');
  1254.         return $this->adminJson(['objectbricks' => $list]);
  1255.     }
  1256.     /**
  1257.      * See http://www.pimcore.org/issues/browse/PIMCORE-2358
  1258.      * Add option to export/import all class definitions/brick definitions etc. at once
  1259.      */
  1260.     /**
  1261.      * @Route("/bulk-import", name="bulkimport", methods={"POST"})
  1262.      *
  1263.      * @param Request $request
  1264.      *
  1265.      * @return JsonResponse
  1266.      */
  1267.     public function bulkImportAction(Request $request)
  1268.     {
  1269.         $result = [];
  1270.         $tmpName $_FILES['Filedata']['tmp_name'];
  1271.         $json file_get_contents($tmpName);
  1272.         $tmpName PIMCORE_SYSTEM_TEMP_DIRECTORY '/bulk-import-' uniqid() . '.tmp';
  1273.         file_put_contents($tmpName$json);
  1274.         Session::useSession(function (AttributeBagInterface $session) use ($tmpName) {
  1275.             $session->set('class_bulk_import_file'$tmpName);
  1276.         }, 'pimcore_objects');
  1277.         $json json_decode($jsontrue);
  1278.         foreach ($json as $groupName => $group) {
  1279.             foreach ($group as $groupItem) {
  1280.                 $displayName null;
  1281.                 $icon null;
  1282.                 if ($groupName == 'class') {
  1283.                     $name $groupItem['name'];
  1284.                     $icon 'class';
  1285.                 } elseif ($groupName == 'customlayout') {
  1286.                     $className $groupItem['className'];
  1287.                     $layoutData = ['className' => $className'name' => $groupItem['name']];
  1288.                     $name base64_encode(json_encode($layoutData));
  1289.                     $displayName $className ' / ' $groupItem['name'];
  1290.                     $icon 'custom_views';
  1291.                 } else {
  1292.                     if ($groupName == 'objectbrick') {
  1293.                         $icon 'objectbricks';
  1294.                     } elseif ($groupName == 'fieldcollection') {
  1295.                         $icon 'fieldcollection';
  1296.                     }
  1297.                     $name $groupItem['key'];
  1298.                 }
  1299.                 if (!$displayName) {
  1300.                     $displayName $name;
  1301.                 }
  1302.                 $result[] = ['icon' => $icon'checked' => true'type' => $groupName'name' => $name'displayName' => $displayName];
  1303.             }
  1304.         }
  1305.         $response $this->adminJson(['success' => true'data' => $result]);
  1306.         $response->headers->set('Content-Type''text/html');
  1307.         return $response;
  1308.     }
  1309.     /**
  1310.      * See http://www.pimcore.org/issues/browse/PIMCORE-2358
  1311.      * Add option to export/import all class definitions/brick definitions etc. at once
  1312.      */
  1313.     /**
  1314.      * @Route("/bulk-commit", name="bulkcommit", methods={"POST"})
  1315.      *
  1316.      * @param Request $request
  1317.      *
  1318.      * @return JsonResponse
  1319.      *
  1320.      * @throws \Exception
  1321.      */
  1322.     public function bulkCommitAction(Request $request)
  1323.     {
  1324.         $data json_decode($request->get('data'), true);
  1325.         $session Session::get('pimcore_objects');
  1326.         $filename $session->get('class_bulk_import_file');
  1327.         $json = @file_get_contents($filename);
  1328.         $json json_decode($jsontrue);
  1329.         $type $data['type'];
  1330.         $name $data['name'];
  1331.         $list $json[$type];
  1332.         foreach ($list as $item) {
  1333.             unset($item['creationDate']);
  1334.             unset($item['modificationDate']);
  1335.             unset($item['userOwner']);
  1336.             unset($item['userModification']);
  1337.             if ($type == 'class' && $item['name'] == $name) {
  1338.                 $class DataObject\ClassDefinition::getByName($name);
  1339.                 if (!$class) {
  1340.                     $class = new DataObject\ClassDefinition();
  1341.                     $class->setName($name);
  1342.                 }
  1343.                 $success DataObject\ClassDefinition\Service::importClassDefinitionFromJson($classjson_encode($item), true);
  1344.                 return $this->adminJson(['success' => $success !== false]);
  1345.             } elseif ($type == 'objectbrick' && $item['key'] == $name) {
  1346.                 if (!$brick DataObject\Objectbrick\Definition::getByKey($name)) {
  1347.                     $brick = new DataObject\Objectbrick\Definition();
  1348.                     $brick->setKey($name);
  1349.                 }
  1350.                 $success DataObject\ClassDefinition\Service::importObjectBrickFromJson($brickjson_encode($item), true);
  1351.                 return $this->adminJson(['success' => $success !== false]);
  1352.             } elseif ($type == 'fieldcollection' && $item['key'] == $name) {
  1353.                 if (!$fieldCollection DataObject\Fieldcollection\Definition::getByKey($name)) {
  1354.                     $fieldCollection = new DataObject\Fieldcollection\Definition();
  1355.                     $fieldCollection->setKey($name);
  1356.                 }
  1357.                 $success DataObject\ClassDefinition\Service::importFieldCollectionFromJson($fieldCollectionjson_encode($item), true);
  1358.                 return $this->adminJson(['success' => $success !== false]);
  1359.             } elseif ($type == 'customlayout') {
  1360.                 $layoutData json_decode(base64_decode($data['name']), true);
  1361.                 $className $layoutData['className'];
  1362.                 $layoutName $layoutData['name'];
  1363.                 if ($item['name'] == $layoutName && $item['className'] == $className) {
  1364.                     $class DataObject\ClassDefinition::getByName($className);
  1365.                     if (!$class) {
  1366.                         throw new \Exception('Class does not exist');
  1367.                     }
  1368.                     $classId $class->getId();
  1369.                     $layoutList = new DataObject\ClassDefinition\CustomLayout\Listing();
  1370.                     $layoutList->setFilter(function (DataObject\ClassDefinition\CustomLayout $layout) use ($layoutName$classId) {
  1371.                         return $layout->getName() === $layoutName && $layout->getClassId() === $classId;
  1372.                     });
  1373.                     $layoutList $layoutList->load();
  1374.                     $layoutDefinition null;
  1375.                     if ($layoutList) {
  1376.                         $layoutDefinition $layoutList[0];
  1377.                     }
  1378.                     if (!$layoutDefinition) {
  1379.                         $layoutDefinition = new DataObject\ClassDefinition\CustomLayout();
  1380.                         $layoutDefinition->setName($layoutName);
  1381.                         $layoutDefinition->setClassId($classId);
  1382.                     }
  1383.                     try {
  1384.                         $layoutDefinition->setDescription($item['description']);
  1385.                         $layoutDef DataObject\ClassDefinition\Service::generateLayoutTreeFromArray($item['layoutDefinitions'], true);
  1386.                         $layoutDefinition->setLayoutDefinitions($layoutDef);
  1387.                         $layoutDefinition->save();
  1388.                     } catch (\Exception $e) {
  1389.                         Logger::error($e->getMessage());
  1390.                         return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  1391.                     }
  1392.                 }
  1393.             }
  1394.         }
  1395.         return $this->adminJson(['success' => true]);
  1396.     }
  1397.     /**
  1398.      * See http://www.pimcore.org/issues/browse/PIMCORE-2358
  1399.      * Add option to export/import all class definitions/brick definitions etc. at once
  1400.      */
  1401.     /**
  1402.      * @Route("/bulk-export-prepare", name="bulkexportprepare", methods={"POST"})
  1403.      *
  1404.      * @param Request $request
  1405.      *
  1406.      * @return Response
  1407.      */
  1408.     public function bulkExportPrepareAction(Request $request)
  1409.     {
  1410.         $data $request->get('data');
  1411.         Session::useSession(function (AttributeBagInterface $session) use ($data) {
  1412.             $session->set('class_bulk_export_settings'$data);
  1413.         }, 'pimcore_objects');
  1414.         return $this->adminJson(['success' => true]);
  1415.     }
  1416.     /**
  1417.      * @Route("/bulk-export", name="bulkexport", methods={"GET"})
  1418.      *
  1419.      * @param Request $request
  1420.      *
  1421.      * @return Response
  1422.      */
  1423.     public function bulkExportAction(Request $request)
  1424.     {
  1425.         $result = [];
  1426.         $fieldCollections = new DataObject\Fieldcollection\Definition\Listing();
  1427.         $fieldCollections $fieldCollections->load();
  1428.         foreach ($fieldCollections as $fieldCollection) {
  1429.             $result[] = [
  1430.                 'icon' => 'fieldcollection',
  1431.                 'checked' => true,
  1432.                 'type' => 'fieldcollection',
  1433.                 'name' => $fieldCollection->getKey(),
  1434.                 'displayName' => $fieldCollection->getKey(),
  1435.             ];
  1436.         }
  1437.         $classes = new DataObject\ClassDefinition\Listing();
  1438.         $classes->setOrder('ASC');
  1439.         $classes->setOrderKey('id');
  1440.         $classes $classes->load();
  1441.         foreach ($classes as $class) {
  1442.             $result[] = [
  1443.                 'icon' => 'class',
  1444.                 'checked' => true,
  1445.                 'type' => 'class',
  1446.                 'name' => $class->getName(),
  1447.                 'displayName' => $class->getName(),
  1448.             ];
  1449.         }
  1450.         $objectBricks = new DataObject\Objectbrick\Definition\Listing();
  1451.         $objectBricks $objectBricks->load();
  1452.         foreach ($objectBricks as $objectBrick) {
  1453.             $result[] = [
  1454.                 'icon' => 'objectbricks',
  1455.                 'checked' => true,
  1456.                 'type' => 'objectbrick',
  1457.                 'name' => $objectBrick->getKey(),
  1458.                 'displayName' => $objectBrick->getKey(),
  1459.             ];
  1460.         }
  1461.         $customLayouts = new DataObject\ClassDefinition\CustomLayout\Listing();
  1462.         $customLayouts $customLayouts->load();
  1463.         foreach ($customLayouts as $customLayout) {
  1464.             $class DataObject\ClassDefinition::getById($customLayout->getClassId());
  1465.             $displayName $class->getName() . ' / ' .  $customLayout->getName();
  1466.             $result[] = [
  1467.                 'icon' => 'custom_views',
  1468.                 'checked' => true,
  1469.                 'type' => 'customlayout',
  1470.                 'name' => $customLayout->getId(),
  1471.                 'displayName' => $displayName,
  1472.             ];
  1473.         }
  1474.         return new JsonResponse(['success' => true'data' => $result]);
  1475.     }
  1476.     /**
  1477.      * @Route("/do-bulk-export", name="dobulkexport", methods={"GET"})
  1478.      *
  1479.      * @param Request $request
  1480.      *
  1481.      * @return Response
  1482.      */
  1483.     public function doBulkExportAction(Request $request)
  1484.     {
  1485.         $session Session::get('pimcore_objects');
  1486.         $list $session->get('class_bulk_export_settings');
  1487.         $list json_decode($listtrue);
  1488.         $result = [];
  1489.         foreach ($list as $item) {
  1490.             if ($item['type'] == 'fieldcollection') {
  1491.                 if ($fieldCollection DataObject\Fieldcollection\Definition::getByKey($item['name'])) {
  1492.                     $fieldCollectionJson json_decode(DataObject\ClassDefinition\Service::generateFieldCollectionJson($fieldCollection));
  1493.                     $fieldCollectionJson->key $item['name'];
  1494.                     $result['fieldcollection'][] = $fieldCollectionJson;
  1495.                 }
  1496.             } elseif ($item['type'] == 'class') {
  1497.                 if ($class DataObject\ClassDefinition::getByName($item['name'])) {
  1498.                     $data json_decode(DataObject\ClassDefinition\Service::generateClassDefinitionJson($class));
  1499.                     $data->name $item['name'];
  1500.                     $result['class'][] = $data;
  1501.                 }
  1502.             } elseif ($item['type'] == 'objectbrick') {
  1503.                 if ($objectBrick DataObject\Objectbrick\Definition::getByKey($item['name'])) {
  1504.                     $objectBrickJson json_decode(DataObject\ClassDefinition\Service::generateObjectBrickJson($objectBrick));
  1505.                     $objectBrickJson->key $item['name'];
  1506.                     $result['objectbrick'][] = $objectBrickJson;
  1507.                 }
  1508.             } elseif ($item['type'] == 'customlayout') {
  1509.                 if ($customLayout DataObject\ClassDefinition\CustomLayout::getById($item['name'])) {
  1510.                     $classId $customLayout->getClassId();
  1511.                     $class DataObject\ClassDefinition::getById($classId);
  1512.                     $customLayoutJson json_decode(DataObject\ClassDefinition\Service::generateCustomLayoutJson($customLayout));
  1513.                     $customLayoutJson->name $customLayout->getName();
  1514.                     $customLayoutJson->className $class->getName();
  1515.                     $result['customlayout'][] = $customLayoutJson;
  1516.                 }
  1517.             }
  1518.         }
  1519.         $result json_encode($resultJSON_PRETTY_PRINT);
  1520.         $response = new Response($result);
  1521.         $response->headers->set('Content-type''application/json');
  1522.         $response->headers->set('Content-Disposition''attachment; filename="bulk_export.json"');
  1523.         return $response;
  1524.     }
  1525.     /**
  1526.      * @param ControllerEvent $event
  1527.      */
  1528.     public function onKernelControllerEvent(ControllerEvent $event)
  1529.     {
  1530.         if (!$event->isMainRequest()) {
  1531.             return;
  1532.         }
  1533.         // check permissions
  1534.         $unrestrictedActions = [
  1535.             'getTreeAction''fieldcollectionListAction''fieldcollectionTreeAction''fieldcollectionGetAction',
  1536.             'getClassDefinitionForColumnConfigAction''objectbrickListAction''objectbrickTreeAction''objectbrickGetAction',
  1537.         ];
  1538.         $this->checkActionPermission($event'classes'$unrestrictedActions);
  1539.     }
  1540.     /**
  1541.      * @Route("/get-fieldcollection-usages", name="getfieldcollectionusages", methods={"GET"})
  1542.      *
  1543.      * @param Request $request
  1544.      *
  1545.      * @return Response
  1546.      */
  1547.     public function getFieldcollectionUsagesAction(Request $request)
  1548.     {
  1549.         $key $request->get('key');
  1550.         $result = [];
  1551.         $classes = new DataObject\ClassDefinition\Listing();
  1552.         $classes $classes->load();
  1553.         foreach ($classes as $class) {
  1554.             $fieldDefs $class->getFieldDefinitions();
  1555.             foreach ($fieldDefs as $fieldDef) {
  1556.                 if ($fieldDef instanceof DataObject\ClassDefinition\Data\Fieldcollections) {
  1557.                     $allowedKeys $fieldDef->getAllowedTypes();
  1558.                     if (is_array($allowedKeys) && in_array($key$allowedKeys)) {
  1559.                         $result[] = [
  1560.                             'class' => $class->getName(),
  1561.                             'field' => $fieldDef->getName(),
  1562.                         ];
  1563.                     }
  1564.                 }
  1565.             }
  1566.         }
  1567.         return $this->adminJson($result);
  1568.     }
  1569.     /**
  1570.      * @Route("/get-bricks-usages", name="getbrickusages", methods={"GET"})
  1571.      *
  1572.      * @param Request $request
  1573.      *
  1574.      * @return Response
  1575.      */
  1576.     public function getBrickUsagesAction(Request $request)
  1577.     {
  1578.         $classId $request->get('classId');
  1579.         $myclass DataObject\ClassDefinition::getById($classId);
  1580.         $result = [];
  1581.         $brickDefinitions = new DataObject\Objectbrick\Definition\Listing();
  1582.         $brickDefinitions $brickDefinitions->load();
  1583.         foreach ($brickDefinitions as $brickDefinition) {
  1584.             $classes $brickDefinition->getClassDefinitions();
  1585.             foreach ($classes as $class) {
  1586.                 if ($myclass->getName() == $class['classname']) {
  1587.                     $result[] = [
  1588.                         'objectbrick' => $brickDefinition->getKey(),
  1589.                         'field' => $class['fieldname'],
  1590.                     ];
  1591.                 }
  1592.             }
  1593.         }
  1594.         return $this->adminJson($result);
  1595.     }
  1596.     /**
  1597.      * @Route("/get-icons", name="geticons", methods={"GET"})
  1598.      *
  1599.      * @param Request $request
  1600.      * @param EventDispatcherInterface $eventDispatcher
  1601.      *
  1602.      * @return Response
  1603.      */
  1604.     public function getIconsAction(Request $requestEventDispatcherInterface $eventDispatcher)
  1605.     {
  1606.         $classId $request->get('classId');
  1607.         $iconDir PIMCORE_WEB_ROOT '/bundles/pimcoreadmin/img';
  1608.         $classIcons rscandir($iconDir '/object-icons/');
  1609.         $colorIcons rscandir($iconDir '/flat-color-icons/');
  1610.         $twemoji rscandir($iconDir '/twemoji/');
  1611.         $icons array_merge($classIcons$colorIcons$twemoji);
  1612.         foreach ($icons as &$icon) {
  1613.             $icon str_replace(PIMCORE_WEB_ROOT''$icon);
  1614.         }
  1615.         $event = new GenericEvent($this, [
  1616.             'icons' => $icons,
  1617.             'classId' => $classId,
  1618.         ]);
  1619.         $eventDispatcher->dispatch($eventAdminEvents::CLASS_OBJECT_ICONS_PRE_SEND_DATA);
  1620.         $icons $event->getArgument('icons');
  1621.         $result = [];
  1622.         foreach ($icons as $icon) {
  1623.             $content file_get_contents(PIMCORE_WEB_ROOT $icon);
  1624.             $result[] = [
  1625.                 'text' => sprintf('<img src="data:%s;base64,%s"/>'mime_content_type(PIMCORE_WEB_ROOT $icon), base64_encode($content)),
  1626.                 'value' => $icon,
  1627.             ];
  1628.         }
  1629.         return $this->adminJson($result);
  1630.     }
  1631.     /**
  1632.      * @Route("/suggest-class-identifier", name="suggestclassidentifier")
  1633.      *
  1634.      * @return Response
  1635.      */
  1636.     public function suggestClassIdentifierAction()
  1637.     {
  1638.         $db Db::get();
  1639.         $maxId $db->fetchOne('SELECT MAX(CAST(id AS SIGNED)) FROM classes;');
  1640.         $existingIds $db->fetchFirstColumn('select LOWER(id) from classes');
  1641.         $result = [
  1642.             'suggestedIdentifier' => $maxId $maxId 1,
  1643.             'existingIds' => $existingIds,
  1644.             ];
  1645.         return $this->adminJson($result);
  1646.     }
  1647.     /**
  1648.      * @Route("/suggest-custom-layout-identifier", name="suggestcustomlayoutidentifier")
  1649.      *
  1650.      * @param Request $request
  1651.      *
  1652.      * @return Response
  1653.      */
  1654.     public function suggestCustomLayoutIdentifierAction(Request $request)
  1655.     {
  1656.         $classId $request->get('classId');
  1657.         $identifier DataObject\ClassDefinition\CustomLayout::getIdentifier($classId);
  1658.         $list = new DataObject\ClassDefinition\CustomLayout\Listing();
  1659.         $list $list->load();
  1660.         $existingIds = [];
  1661.         $existingNames = [];
  1662.         foreach ($list as $item) {
  1663.             $existingIds[] = $item->getId();
  1664.             if ($item->getClassId() == $classId) {
  1665.                 $existingNames[] = $item->getName();
  1666.             }
  1667.         }
  1668.         $result = [
  1669.             'suggestedIdentifier' => $identifier,
  1670.             'existingIds' => $existingIds,
  1671.             'existingNames' => $existingNames,
  1672.             ];
  1673.         return $this->adminJson($result);
  1674.     }
  1675.     /**
  1676.      * @Route("/text-layout-preview", name="textlayoutpreview")
  1677.      *
  1678.      * @param Request $request
  1679.      *
  1680.      * @return Response
  1681.      */
  1682.     public function textLayoutPreviewAction(Request $request)
  1683.     {
  1684.         $objPath $request->get('previewObject''');
  1685.         $className '\\Pimcore\\Model\\DataObject\\' $request->get('className');
  1686.         $obj DataObject::getByPath($objPath) ?? new $className();
  1687.         $textLayout = new DataObject\ClassDefinition\Layout\Text();
  1688.         $context = [
  1689.           'data' => $request->get('renderingData'),
  1690.         ];
  1691.         if ($renderingClass $request->get('renderingClass')) {
  1692.             $textLayout->setRenderingClass($renderingClass);
  1693.         }
  1694.         if ($staticHtml $request->get('html')) {
  1695.             $textLayout->setHtml($staticHtml);
  1696.         }
  1697.         $html $textLayout->enrichLayoutDefinition($obj$context)->getHtml();
  1698.         $content =
  1699.             "<html>\n" .
  1700.             "<head>\n" .
  1701.             '<style type="text/css">' "\n" .
  1702.             file_get_contents(PIMCORE_WEB_ROOT '/bundles/pimcoreadmin/css/admin.css') .
  1703.             "</style>\n" .
  1704.             "</head>\n\n" .
  1705.             "<body class='objectlayout_element_text'>\n" .
  1706.             $html .
  1707.             "\n\n</body>\n" .
  1708.             "</html>\n";
  1709.         $response = new Response($content);
  1710.         $response->headers->set('Content-Type''text/html');
  1711.         return $response;
  1712.     }
  1713.     /**
  1714.      * @Route("/video-supported-types", name="videosupportedTypestypes")
  1715.      *
  1716.      * @param Request $request
  1717.      *
  1718.      * @return Response
  1719.      */
  1720.     public function videoAllowedTypesAction(Request $request)
  1721.     {
  1722.         $videoDef = new DataObject\ClassDefinition\Data\Video();
  1723.         $res = [];
  1724.         foreach ($videoDef->getSupportedTypes() as $type) {
  1725.             $res[] = [
  1726.                 'key' => $type,
  1727.                 'value' => $this->trans($type),
  1728.             ];
  1729.         }
  1730.         return $this->adminJson($res);
  1731.     }
  1732. }