vendor/pimcore/pimcore/models/DataObject/ClassDefinition.php line 300

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\Model\DataObject;
  15. use Pimcore\Cache;
  16. use Pimcore\DataObject\ClassBuilder\FieldDefinitionDocBlockBuilderInterface;
  17. use Pimcore\DataObject\ClassBuilder\PHPClassDumperInterface;
  18. use Pimcore\Db;
  19. use Pimcore\Event\DataObjectClassDefinitionEvents;
  20. use Pimcore\Event\Model\DataObject\ClassDefinitionEvent;
  21. use Pimcore\Event\Traits\RecursionBlockingEventDispatchHelperTrait;
  22. use Pimcore\Logger;
  23. use Pimcore\Model;
  24. use Pimcore\Model\DataObject;
  25. use Pimcore\Model\DataObject\ClassDefinition\Data\FieldDefinitionEnrichmentInterface;
  26. /**
  27.  * @method \Pimcore\Model\DataObject\ClassDefinition\Dao getDao()
  28.  */
  29. final class ClassDefinition extends Model\AbstractModel
  30. {
  31.     use DataObject\ClassDefinition\Helper\VarExport;
  32.     use DataObject\Traits\LocateFileTrait;
  33.     use RecursionBlockingEventDispatchHelperTrait;
  34.     /**
  35.      * @internal
  36.      *
  37.      * @var string|null
  38.      */
  39.     public $id;
  40.     /**
  41.      * @internal
  42.      *
  43.      * @var string|null
  44.      */
  45.     public $name;
  46.     /**
  47.      * @internal
  48.      *
  49.      * @var string
  50.      */
  51.     public $description '';
  52.     /**
  53.      * @internal
  54.      *
  55.      * @var int|null
  56.      */
  57.     public $creationDate;
  58.     /**
  59.      * @internal
  60.      *
  61.      * @var int|null
  62.      */
  63.     public $modificationDate;
  64.     /**
  65.      * @internal
  66.      *
  67.      * @var int|null
  68.      */
  69.     public $userOwner;
  70.     /**
  71.      * @internal
  72.      *
  73.      * @var int|null
  74.      */
  75.     public $userModification;
  76.     /**
  77.      * @internal
  78.      *
  79.      * @var string
  80.      */
  81.     public $parentClass '';
  82.     /**
  83.      * Comma separated list of interfaces
  84.      *
  85.      * @internal
  86.      *
  87.      * @var string|null
  88.      */
  89.     public $implementsInterfaces;
  90.     /**
  91.      * Name of the listing parent class if set
  92.      *
  93.      * @internal
  94.      *
  95.      * @var string
  96.      */
  97.     public $listingParentClass '';
  98.     /**
  99.      * @internal
  100.      *
  101.      * @var string
  102.      */
  103.     public $useTraits '';
  104.     /**
  105.      * @internal
  106.      *
  107.      * @var string
  108.      */
  109.     public $listingUseTraits '';
  110.     /**
  111.      * @internal
  112.      *
  113.      * @var bool
  114.      */
  115.     protected $encryption false;
  116.     /**
  117.      * @internal
  118.      *
  119.      * @var array
  120.      */
  121.     protected $encryptedTables = [];
  122.     /**
  123.      * @internal
  124.      *
  125.      * @var bool
  126.      */
  127.     public $allowInherit false;
  128.     /**
  129.      * @internal
  130.      *
  131.      * @var bool
  132.      */
  133.     public $allowVariants false;
  134.     /**
  135.      * @internal
  136.      *
  137.      * @var bool
  138.      */
  139.     public $showVariants false;
  140.     /**
  141.      * @internal
  142.      *
  143.      * @var DataObject\ClassDefinition\Data[]
  144.      */
  145.     public array $fieldDefinitions = [];
  146.     /**
  147.      * @internal
  148.      *
  149.      * @var DataObject\ClassDefinition\Layout|null
  150.      */
  151.     public $layoutDefinitions;
  152.     /**
  153.      * @internal
  154.      *
  155.      * @var string
  156.      */
  157.     public $icon;
  158.     /**
  159.      * @internal
  160.      *
  161.      * @var string
  162.      */
  163.     public $previewUrl;
  164.     /**
  165.      * @internal
  166.      *
  167.      * @var string
  168.      */
  169.     public $group;
  170.     /**
  171.      * @internal
  172.      *
  173.      * @var bool
  174.      */
  175.     public $showAppLoggerTab false;
  176.     /**
  177.      * @internal
  178.      *
  179.      * @var string
  180.      */
  181.     public $linkGeneratorReference;
  182.     /**
  183.      * @internal
  184.      *
  185.      * @var string|null
  186.      */
  187.     public $previewGeneratorReference;
  188.     /**
  189.      * @internal
  190.      *
  191.      * @var array
  192.      */
  193.     public $compositeIndices = [];
  194.     /**
  195.      * @internal
  196.      *
  197.      * @var bool
  198.      */
  199.     public $generateTypeDeclarations true;
  200.     /**
  201.      * @internal
  202.      *
  203.      * @var bool
  204.      */
  205.     public $showFieldLookup false;
  206.     /**
  207.      * @internal
  208.      *
  209.      * @var array
  210.      */
  211.     public $propertyVisibility = [
  212.         'grid' => [
  213.             'id' => true,
  214.             'path' => true,
  215.             'published' => true,
  216.             'modificationDate' => true,
  217.             'creationDate' => true,
  218.         ],
  219.         'search' => [
  220.             'id' => true,
  221.             'path' => true,
  222.             'published' => true,
  223.             'modificationDate' => true,
  224.             'creationDate' => true,
  225.         ],
  226.     ];
  227.     /**
  228.      * @internal
  229.      *
  230.      * @var bool
  231.      */
  232.     public $enableGridLocking false;
  233.     /**
  234.      * @internal
  235.      *
  236.      * @var ClassDefinition\Data[]
  237.      */
  238.     private array $deletedDataComponents = [];
  239.     /**
  240.      * @param string $id
  241.      * @param bool $force
  242.      *
  243.      * @return null|ClassDefinition
  244.      *
  245.      * @throws \Exception
  246.      */
  247.     public static function getById(string $id$force false)
  248.     {
  249.         $cacheKey 'class_' $id;
  250.         try {
  251.             if ($force) {
  252.                 throw new \Exception('Forced load');
  253.             }
  254.             $class \Pimcore\Cache\Runtime::get($cacheKey);
  255.             if (!$class) {
  256.                 throw new \Exception('Class in registry is null');
  257.             }
  258.         } catch (\Exception $e) {
  259.             try {
  260.                 $class = new self();
  261.                 $name $class->getDao()->getNameById($id);
  262.                 $definitionFile $class->getDefinitionFile($name);
  263.                 $class = @include $definitionFile;
  264.                 if (!$class instanceof self) {
  265.                     throw new \Exception('Class definition with name ' $name ' or ID ' $id ' does not exist');
  266.                 }
  267.                 $class->setId($id);
  268.                 \Pimcore\Cache\Runtime::set($cacheKey$class);
  269.             } catch (\Exception $e) {
  270.                 Logger::info($e->getMessage());
  271.                 return null;
  272.             }
  273.         }
  274.         return $class;
  275.     }
  276.     /**
  277.      * @param string $name
  278.      *
  279.      * @return self|null
  280.      *
  281.      * @throws \Exception
  282.      */
  283.     public static function getByName($name)
  284.     {
  285.         try {
  286.             $class = new self();
  287.             $id $class->getDao()->getIdByName($name);
  288.             return self::getById($id);
  289.         } catch (Model\Exception\NotFoundException $e) {
  290.             return null;
  291.         }
  292.     }
  293.     /**
  294.      * @param array $values
  295.      *
  296.      * @return self
  297.      */
  298.     public static function create($values = [])
  299.     {
  300.         $class = new self();
  301.         $class->setValues($values);
  302.         return $class;
  303.     }
  304.     /**
  305.      * @internal
  306.      *
  307.      * @param string $name
  308.      */
  309.     public function rename($name)
  310.     {
  311.         $this->deletePhpClasses();
  312.         $this->getDao()->updateClassNameInObjects($name);
  313.         $this->setName($name);
  314.         $this->save();
  315.     }
  316.     /**
  317.      * @param mixed $data
  318.      *
  319.      * @internal
  320.      */
  321.     public static function cleanupForExport(&$data)
  322.     {
  323.         if (!is_object($data)) {
  324.             return;
  325.         }
  326.         if ($data instanceof DataObject\ClassDefinition\Data\VarExporterInterface) {
  327.             $blockedVars $data->resolveBlockedVars();
  328.             foreach ($blockedVars as $blockedVar) {
  329.                 if (isset($data->{$blockedVar})) {
  330.                     unset($data->{$blockedVar});
  331.                 }
  332.             }
  333.             if (isset($data->blockedVarsForExport)) {
  334.                 unset($data->blockedVarsForExport);
  335.             }
  336.         }
  337.         if (method_exists($data'getChildren')) {
  338.             $children $data->getChildren();
  339.             if (is_array($children)) {
  340.                 foreach ($children as $child) {
  341.                     self::cleanupForExport($child);
  342.                 }
  343.             }
  344.         }
  345.     }
  346.     /**
  347.      * @return bool
  348.      */
  349.     private function exists()
  350.     {
  351.         $name $this->getDao()->getNameById($this->getId());
  352.         return is_string($name);
  353.     }
  354.     /**
  355.      * @param bool $saveDefinitionFile
  356.      *
  357.      * @throws \Exception
  358.      * @throws DataObject\Exception\DefinitionWriteException
  359.      */
  360.     public function save($saveDefinitionFile true)
  361.     {
  362.         if ($saveDefinitionFile && !$this->isWritable()) {
  363.             throw new DataObject\Exception\DefinitionWriteException();
  364.         }
  365.         $fieldDefinitions $this->getFieldDefinitions();
  366.         foreach ($fieldDefinitions as $fd) {
  367.             if ($fd->isForbiddenName()) {
  368.                 throw new \Exception(sprintf('Forbidden name used for field definition: %s'$fd->getName()));
  369.             }
  370.             if ($fd instanceof DataObject\ClassDefinition\Data\DataContainerAwareInterface) {
  371.                 $fd->preSave($this);
  372.             }
  373.         }
  374.         if (!$this->getId()) {
  375.             $db Db::get();
  376.             $maxId $db->fetchOne('SELECT MAX(CAST(id AS SIGNED)) FROM classes;');
  377.             $maxId $maxId $maxId 1;
  378.             $this->setId((string) $maxId);
  379.         }
  380.         if (!preg_match('/[a-zA-Z][a-zA-Z0-9_]+/'$this->getName())) {
  381.             throw new \Exception(sprintf('Invalid name for class definition: %s'$this->getName()));
  382.         }
  383.         if (!preg_match('/[a-zA-Z0-9]([a-zA-Z0-9_]+)?/'$this->getId())) {
  384.             throw new \Exception(sprintf('Invalid ID `%s` for class definition %s'$this->getId(), $this->getName()));
  385.         }
  386.         foreach (['parentClass''listingParentClass''useTraits''listingUseTraits'] as $propertyName) {
  387.             $propertyValue $this->{'get'.ucfirst($propertyName)}();
  388.             if ($propertyValue && !preg_match('/^[a-zA-Z_\x7f-\xff\\\][a-zA-Z0-9_\x7f-\xff\\\ ,]*$/'$propertyValue)) {
  389.                 throw new \Exception(sprintf('Invalid %s value for class definition: %s'$propertyName,
  390.                     $this->getParentClass()));
  391.             }
  392.         }
  393.         $isUpdate $this->exists();
  394.         if (!$isUpdate) {
  395.             $this->dispatchEvent(new ClassDefinitionEvent($this), DataObjectClassDefinitionEvents::PRE_ADD);
  396.         } else {
  397.             $this->dispatchEvent(new ClassDefinitionEvent($this), DataObjectClassDefinitionEvents::PRE_UPDATE);
  398.         }
  399.         $this->setModificationDate(time());
  400.         $this->getDao()->save($isUpdate);
  401.         $this->generateClassFiles($saveDefinitionFile);
  402.         // empty object cache
  403.         try {
  404.             Cache::clearTag('class_'.$this->getId());
  405.         } catch (\Exception $e) {
  406.         }
  407.         foreach ($fieldDefinitions as $fd) {
  408.             if ($fd instanceof DataObject\ClassDefinition\Data\DataContainerAwareInterface) {
  409.                 $fd->postSave($this);
  410.             }
  411.         }
  412.         if ($isUpdate) {
  413.             $this->dispatchEvent(new ClassDefinitionEvent($this), DataObjectClassDefinitionEvents::POST_UPDATE);
  414.         } else {
  415.             $this->dispatchEvent(new ClassDefinitionEvent($this), DataObjectClassDefinitionEvents::POST_ADD);
  416.         }
  417.         $this->deleteDeletedDataComponentsInCustomLayout();
  418.     }
  419.     /**
  420.      * @param bool $generateDefinitionFile
  421.      *
  422.      * @throws \Exception
  423.      *
  424.      * @internal
  425.      */
  426.     public function generateClassFiles($generateDefinitionFile true)
  427.     {
  428.         \Pimcore::getContainer()->get(PHPClassDumperInterface::class)->dumpPHPClasses($this);
  429.         if ($generateDefinitionFile) {
  430.             // save definition as a php file
  431.             $definitionFile $this->getDefinitionFile();
  432.             if (!is_writable(dirname($definitionFile)) || (is_file($definitionFile) && !is_writable($definitionFile))) {
  433.                 throw new \Exception(
  434.                     'Cannot write definition file in: '.$definitionFile.' please check write permission on this directory.'
  435.                 );
  436.             }
  437.             /** @var self $clone */
  438.             $clone DataObject\Service::cloneDefinition($this);
  439.             $clone->setDao(null);
  440.             $clone->fieldDefinitions = [];
  441.             self::cleanupForExport($clone->layoutDefinitions);
  442.             $exportedClass var_export($clonetrue);
  443.             $data '<?php';
  444.             $data .= "\n\n";
  445.             $data .= $this->getInfoDocBlock();
  446.             $data .= "\n\n";
  447.             $data .= 'return '.$exportedClass.";\n";
  448.             \Pimcore\File::putPhpFile($definitionFile$data);
  449.         }
  450.     }
  451.     /**
  452.      * @return string
  453.      *
  454.      * @internal
  455.      */
  456.     protected function getInfoDocBlock(): string
  457.     {
  458.         $cd '/**' "\n";
  459.         $cd .= ' * Inheritance: '.($this->getAllowInherit() ? 'yes' 'no')."\n";
  460.         $cd .= ' * Variants: '.($this->getAllowVariants() ? 'yes' 'no')."\n";
  461.         if ($description $this->getDescription()) {
  462.             $description str_replace(['/**''*/''//'], ''$description);
  463.             $description str_replace("\n""\n * "$description);
  464.             $cd .= ' * '.$description."\n";
  465.         }
  466.         $cd .= " *\n";
  467.         $cd .= " * Fields Summary:\n";
  468.         $fieldDefinitionDocBlockBuilder \Pimcore::getContainer()->get(FieldDefinitionDocBlockBuilderInterface::class);
  469.         foreach ($this->getFieldDefinitions() as $fieldDefinition) {
  470.             $cd .= ' * ' str_replace("\n""\n * "trim($fieldDefinitionDocBlockBuilder->buildFieldDefinitionDocBlock($fieldDefinition))) . "\n";
  471.         }
  472.         $cd .= ' */';
  473.         return $cd;
  474.     }
  475.     public function delete()
  476.     {
  477.         $this->dispatchEvent(new ClassDefinitionEvent($this), DataObjectClassDefinitionEvents::PRE_DELETE);
  478.         // delete all objects using this class
  479.         $list = new Listing();
  480.         $list->setCondition('o_classId = ?'$this->getId());
  481.         $list->load();
  482.         foreach ($list->getObjects() as $o) {
  483.             $o->delete();
  484.         }
  485.         $this->deletePhpClasses();
  486.         // empty object cache
  487.         try {
  488.             Cache::clearTag('class_'.$this->getId());
  489.         } catch (\Exception $e) {
  490.         }
  491.         // empty output cache
  492.         try {
  493.             Cache::clearTag('output');
  494.         } catch (\Exception $e) {
  495.         }
  496.         $customLayouts = new ClassDefinition\CustomLayout\Listing();
  497.         $customLayouts->setCondition('classId = ?'$this->getId());
  498.         $customLayouts $customLayouts->load();
  499.         foreach ($customLayouts as $customLayout) {
  500.             $customLayout->delete();
  501.         }
  502.         $brickListing = new DataObject\Objectbrick\Definition\Listing();
  503.         $brickListing $brickListing->load();
  504.         foreach ($brickListing as $brickDefinition) {
  505.             $modified false;
  506.             $classDefinitions $brickDefinition->getClassDefinitions();
  507.             if (is_array($classDefinitions)) {
  508.                 foreach ($classDefinitions as $key => $classDefinition) {
  509.                     if ($classDefinition['classname'] == $this->getId()) {
  510.                         unset($classDefinitions[$key]);
  511.                         $modified true;
  512.                     }
  513.                 }
  514.             }
  515.             if ($modified) {
  516.                 $brickDefinition->setClassDefinitions($classDefinitions);
  517.                 $brickDefinition->save();
  518.             }
  519.         }
  520.         $this->getDao()->delete();
  521.         $this->dispatchEvent(new ClassDefinitionEvent($this), DataObjectClassDefinitionEvents::POST_DELETE);
  522.     }
  523.     private function deletePhpClasses()
  524.     {
  525.         // delete the class files
  526.         @unlink($this->getPhpClassFile());
  527.         @unlink($this->getPhpListingClassFile());
  528.         @rmdir(dirname($this->getPhpListingClassFile()));
  529.         @unlink($this->getDefinitionFile());
  530.     }
  531.     /**
  532.      * @internal
  533.      *
  534.      * @return bool
  535.      */
  536.     public function isWritable(): bool
  537.     {
  538.         if ($_SERVER['PIMCORE_CLASS_DEFINITION_WRITABLE'] ?? false) {
  539.             return true;
  540.         }
  541.         return !str_starts_with($this->getDefinitionFile(), PIMCORE_CUSTOM_CONFIGURATION_DIRECTORY);
  542.     }
  543.     /**
  544.      * @internal
  545.      *
  546.      * @param string|null $name
  547.      *
  548.      * @return string
  549.      */
  550.     public function getDefinitionFile($name null)
  551.     {
  552.         return $this->locateDefinitionFile($name ?? $this->getName(), 'definition_%s.php');
  553.     }
  554.     /**
  555.      * @internal
  556.      */
  557.     public function getPhpClassFile(): string
  558.     {
  559.         return $this->locateFile(ucfirst($this->getName()), 'DataObject/%s.php');
  560.     }
  561.     /**
  562.      * @internal
  563.      */
  564.     public function getPhpListingClassFile(): string
  565.     {
  566.         return $this->locateFile(ucfirst($this->getName()), 'DataObject/%s/Listing.php');
  567.     }
  568.     /**
  569.      * @return string|null
  570.      */
  571.     public function getId()
  572.     {
  573.         return $this->id;
  574.     }
  575.     /**
  576.      * @return string|null
  577.      */
  578.     public function getName()
  579.     {
  580.         return $this->name;
  581.     }
  582.     /**
  583.      * @return int|null
  584.      */
  585.     public function getCreationDate()
  586.     {
  587.         return $this->creationDate;
  588.     }
  589.     /**
  590.      * @return int|null
  591.      */
  592.     public function getModificationDate()
  593.     {
  594.         return $this->modificationDate;
  595.     }
  596.     /**
  597.      * @return int|null
  598.      */
  599.     public function getUserOwner()
  600.     {
  601.         return $this->userOwner;
  602.     }
  603.     /**
  604.      * @return int|null
  605.      */
  606.     public function getUserModification()
  607.     {
  608.         return $this->userModification;
  609.     }
  610.     /**
  611.      * @param string $id
  612.      *
  613.      * @return $this
  614.      */
  615.     public function setId($id)
  616.     {
  617.         $this->id $id;
  618.         return $this;
  619.     }
  620.     /**
  621.      * @param string $name
  622.      *
  623.      * @return $this
  624.      */
  625.     public function setName($name)
  626.     {
  627.         $this->name $name;
  628.         return $this;
  629.     }
  630.     /**
  631.      * @param int $creationDate
  632.      *
  633.      * @return $this
  634.      */
  635.     public function setCreationDate($creationDate)
  636.     {
  637.         $this->creationDate = (int)$creationDate;
  638.         return $this;
  639.     }
  640.     /**
  641.      * @param int $modificationDate
  642.      *
  643.      * @return $this
  644.      */
  645.     public function setModificationDate($modificationDate)
  646.     {
  647.         $this->modificationDate = (int)$modificationDate;
  648.         return $this;
  649.     }
  650.     /**
  651.      * @param int $userOwner
  652.      *
  653.      * @return $this
  654.      */
  655.     public function setUserOwner($userOwner)
  656.     {
  657.         $this->userOwner = (int)$userOwner;
  658.         return $this;
  659.     }
  660.     /**
  661.      * @param int $userModification
  662.      *
  663.      * @return $this
  664.      */
  665.     public function setUserModification($userModification)
  666.     {
  667.         $this->userModification = (int)$userModification;
  668.         return $this;
  669.     }
  670.     /**
  671.      * @param array $context
  672.      *
  673.      * @return DataObject\ClassDefinition\Data[]
  674.      */
  675.     public function getFieldDefinitions($context = [])
  676.     {
  677.         if (!\Pimcore::inAdmin() || (isset($context['suppressEnrichment']) && $context['suppressEnrichment'])) {
  678.             return $this->fieldDefinitions;
  679.         }
  680.         $enrichedFieldDefinitions = [];
  681.         foreach ($this->fieldDefinitions as $key => $fieldDefinition) {
  682.             $fieldDefinition $this->doEnrichFieldDefinition($fieldDefinition$context);
  683.             $enrichedFieldDefinitions[$key] = $fieldDefinition;
  684.         }
  685.         return $enrichedFieldDefinitions;
  686.     }
  687.     /**
  688.      * @internal
  689.      */
  690.     protected function doEnrichFieldDefinition($fieldDefinition$context = [])
  691.     {
  692.         //TODO Pimcore 11: remove method_exists BC layer
  693.         if ($fieldDefinition instanceof FieldDefinitionEnrichmentInterface || method_exists($fieldDefinition'enrichFieldDefinition')) {
  694.             if (!$fieldDefinition instanceof FieldDefinitionEnrichmentInterface) {
  695.                 trigger_deprecation('pimcore/pimcore''10.1',
  696.                     sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  697.                     'Implement the %s interface instead.'FieldDefinitionEnrichmentInterface::class));
  698.             }
  699.             $context['class'] = $this;
  700.             $fieldDefinition $fieldDefinition->enrichFieldDefinition($context);
  701.         }
  702.         return $fieldDefinition;
  703.     }
  704.     /**
  705.      * @return DataObject\ClassDefinition\Layout|null
  706.      */
  707.     public function getLayoutDefinitions()
  708.     {
  709.         return $this->layoutDefinitions;
  710.     }
  711.     /**
  712.      * @param DataObject\ClassDefinition\Data[] $fieldDefinitions
  713.      *
  714.      * @return $this
  715.      */
  716.     public function setFieldDefinitions(array $fieldDefinitions)
  717.     {
  718.         $this->fieldDefinitions $fieldDefinitions;
  719.         return $this;
  720.     }
  721.     /**
  722.      * @param string $key
  723.      * @param DataObject\ClassDefinition\Data $data
  724.      *
  725.      * @return $this
  726.      */
  727.     public function addFieldDefinition($key$data)
  728.     {
  729.         $this->fieldDefinitions[$key] = $data;
  730.         return $this;
  731.     }
  732.     /**
  733.      * @param string $key
  734.      * @param array $context
  735.      *
  736.      * @return DataObject\ClassDefinition\Data|null
  737.      */
  738.     public function getFieldDefinition($key$context = [])
  739.     {
  740.         if (array_key_exists($key$this->fieldDefinitions)) {
  741.             if (!\Pimcore::inAdmin() || (isset($context['suppressEnrichment']) && $context['suppressEnrichment'])) {
  742.                 return $this->fieldDefinitions[$key];
  743.             }
  744.             $fieldDefinition $this->doEnrichFieldDefinition($this->fieldDefinitions[$key], $context);
  745.             return $fieldDefinition;
  746.         }
  747.         return null;
  748.     }
  749.     /**
  750.      * @param DataObject\ClassDefinition\Layout|null $layoutDefinitions
  751.      *
  752.      * @return $this
  753.      */
  754.     public function setLayoutDefinitions($layoutDefinitions)
  755.     {
  756.         $oldFieldDefinitions null;
  757.         if ($this->layoutDefinitions !== null) {
  758.             $this->setDeletedDataComponents([]);
  759.             $oldFieldDefinitions $this->getFieldDefinitions();
  760.         }
  761.         $this->layoutDefinitions $layoutDefinitions;
  762.         $this->fieldDefinitions = [];
  763.         $this->extractDataDefinitions($this->layoutDefinitions);
  764.         if ($oldFieldDefinitions !== null) {
  765.             $newFieldDefinitions $this->getFieldDefinitions();
  766.             $deletedComponents = [];
  767.             foreach ($oldFieldDefinitions as $fieldDefinition) {
  768.                 if (!array_key_exists($fieldDefinition->getName(), $newFieldDefinitions)) {
  769.                     array_push($deletedComponents$fieldDefinition);
  770.                 }
  771.             }
  772.             $this->setDeletedDataComponents($deletedComponents);
  773.         }
  774.         return $this;
  775.     }
  776.     /**
  777.      * @param DataObject\ClassDefinition\Layout|DataObject\ClassDefinition\Data $def
  778.      */
  779.     private function extractDataDefinitions($def)
  780.     {
  781.         if ($def instanceof DataObject\ClassDefinition\Layout) {
  782.             if ($def->hasChildren()) {
  783.                 foreach ($def->getChildren() as $child) {
  784.                     $this->extractDataDefinitions($child);
  785.                 }
  786.             }
  787.         }
  788.         if ($def instanceof DataObject\ClassDefinition\Data) {
  789.             $existing $this->getFieldDefinition($def->getName());
  790.             if (!$existing && method_exists($def'addReferencedField') && method_exists($def'setReferencedFields')) {
  791.                 $def->setReferencedFields([]);
  792.             }
  793.             if ($existing && method_exists($existing'addReferencedField')) {
  794.                 // this is especially for localized fields which get aggregated here into one field definition
  795.                 // in the case that there are more than one localized fields in the class definition
  796.                 // see also pimcore.object.edit.addToDataFields();
  797.                 $existing->addReferencedField($def);
  798.             } else {
  799.                 $this->addFieldDefinition($def->getName(), $def);
  800.             }
  801.         }
  802.     }
  803.     /**
  804.      * @return string
  805.      */
  806.     public function getParentClass()
  807.     {
  808.         return $this->parentClass;
  809.     }
  810.     /**
  811.      * @return string
  812.      */
  813.     public function getListingParentClass()
  814.     {
  815.         return $this->listingParentClass;
  816.     }
  817.     /**
  818.      * @return string
  819.      */
  820.     public function getUseTraits()
  821.     {
  822.         return $this->useTraits;
  823.     }
  824.     /**
  825.      * @param string $useTraits
  826.      *
  827.      * @return ClassDefinition
  828.      */
  829.     public function setUseTraits($useTraits)
  830.     {
  831.         $this->useTraits = (string) $useTraits;
  832.         return $this;
  833.     }
  834.     /**
  835.      * @return string
  836.      */
  837.     public function getListingUseTraits()
  838.     {
  839.         return $this->listingUseTraits;
  840.     }
  841.     /**
  842.      * @param string $listingUseTraits
  843.      *
  844.      * @return ClassDefinition
  845.      */
  846.     public function setListingUseTraits($listingUseTraits)
  847.     {
  848.         $this->listingUseTraits = (string) $listingUseTraits;
  849.         return $this;
  850.     }
  851.     /**
  852.      * @return bool
  853.      */
  854.     public function getAllowInherit()
  855.     {
  856.         return $this->allowInherit;
  857.     }
  858.     /**
  859.      * @return bool
  860.      */
  861.     public function getAllowVariants()
  862.     {
  863.         return $this->allowVariants;
  864.     }
  865.     /**
  866.      * @param string $parentClass
  867.      *
  868.      * @return $this
  869.      */
  870.     public function setParentClass($parentClass)
  871.     {
  872.         $this->parentClass $parentClass;
  873.         return $this;
  874.     }
  875.     /**
  876.      * @param string $listingParentClass
  877.      *
  878.      * @return $this
  879.      */
  880.     public function setListingParentClass($listingParentClass)
  881.     {
  882.         $this->listingParentClass = (string) $listingParentClass;
  883.         return $this;
  884.     }
  885.     /**
  886.      * @return bool
  887.      */
  888.     public function getEncryption(): bool
  889.     {
  890.         return $this->encryption;
  891.     }
  892.     /**
  893.      * @param bool $encryption
  894.      *
  895.      * @return $this
  896.      */
  897.     public function setEncryption(bool $encryption)
  898.     {
  899.         $this->encryption $encryption;
  900.         return $this;
  901.     }
  902.     /**
  903.      * @internal
  904.      *
  905.      * @param array $tables
  906.      */
  907.     public function addEncryptedTables(array $tables)
  908.     {
  909.         $this->encryptedTables array_unique(array_merge($this->encryptedTables$tables));
  910.     }
  911.     /**
  912.      * @internal
  913.      *
  914.      * @param array $tables
  915.      */
  916.     public function removeEncryptedTables(array $tables)
  917.     {
  918.         foreach ($tables as $table) {
  919.             if (($key array_search($table$this->encryptedTables)) !== false) {
  920.                 unset($this->encryptedTables[$key]);
  921.             }
  922.         }
  923.     }
  924.     /**
  925.      * @internal
  926.      *
  927.      * @param string $table
  928.      *
  929.      * @return bool
  930.      */
  931.     public function isEncryptedTable(string $table): bool
  932.     {
  933.         return (array_search($table$this->encryptedTables) === false) ? false true;
  934.     }
  935.     /**
  936.      * @return bool
  937.      */
  938.     public function hasEncryptedTables(): bool
  939.     {
  940.         return (bool) count($this->encryptedTables);
  941.     }
  942.     /**
  943.      * @internal
  944.      *
  945.      * @param array $encryptedTables
  946.      *
  947.      * @return $this
  948.      */
  949.     public function setEncryptedTables(array $encryptedTables)
  950.     {
  951.         $this->encryptedTables $encryptedTables;
  952.         return $this;
  953.     }
  954.     /**
  955.      * @param bool $allowInherit
  956.      *
  957.      * @return $this
  958.      */
  959.     public function setAllowInherit($allowInherit)
  960.     {
  961.         $this->allowInherit = (bool)$allowInherit;
  962.         return $this;
  963.     }
  964.     /**
  965.      * @param bool $allowVariants
  966.      *
  967.      * @return $this
  968.      */
  969.     public function setAllowVariants($allowVariants)
  970.     {
  971.         $this->allowVariants = (bool)$allowVariants;
  972.         return $this;
  973.     }
  974.     /**
  975.      * @return string
  976.      */
  977.     public function getIcon()
  978.     {
  979.         return $this->icon;
  980.     }
  981.     /**
  982.      * @param string $icon
  983.      *
  984.      * @return $this
  985.      */
  986.     public function setIcon($icon)
  987.     {
  988.         $this->icon $icon;
  989.         return $this;
  990.     }
  991.     /**
  992.      * @return array
  993.      */
  994.     public function getPropertyVisibility()
  995.     {
  996.         return $this->propertyVisibility;
  997.     }
  998.     /**
  999.      * @param array $propertyVisibility
  1000.      *
  1001.      * @return $this
  1002.      */
  1003.     public function setPropertyVisibility($propertyVisibility)
  1004.     {
  1005.         if (is_array($propertyVisibility)) {
  1006.             $this->propertyVisibility $propertyVisibility;
  1007.         }
  1008.         return $this;
  1009.     }
  1010.     /**
  1011.      * @param string $previewUrl
  1012.      *
  1013.      * @return $this
  1014.      */
  1015.     public function setPreviewUrl($previewUrl)
  1016.     {
  1017.         $this->previewUrl $previewUrl;
  1018.         return $this;
  1019.     }
  1020.     /**
  1021.      * @return string
  1022.      */
  1023.     public function getPreviewUrl()
  1024.     {
  1025.         return $this->previewUrl;
  1026.     }
  1027.     /**
  1028.      * @return string
  1029.      */
  1030.     public function getGroup()
  1031.     {
  1032.         return $this->group;
  1033.     }
  1034.     /**
  1035.      * @param string $group
  1036.      *
  1037.      * @return $this
  1038.      */
  1039.     public function setGroup($group)
  1040.     {
  1041.         $this->group $group;
  1042.         return $this;
  1043.     }
  1044.     /**
  1045.      * @param string $description
  1046.      *
  1047.      * @return $this
  1048.      */
  1049.     public function setDescription($description)
  1050.     {
  1051.         $this->description $description;
  1052.         return $this;
  1053.     }
  1054.     /**
  1055.      * @return string
  1056.      */
  1057.     public function getDescription()
  1058.     {
  1059.         return $this->description;
  1060.     }
  1061.     /**
  1062.      * @param bool $showVariants
  1063.      *
  1064.      * @return $this
  1065.      */
  1066.     public function setShowVariants($showVariants)
  1067.     {
  1068.         $this->showVariants = (bool)$showVariants;
  1069.         return $this;
  1070.     }
  1071.     /**
  1072.      * @return bool
  1073.      */
  1074.     public function getShowVariants()
  1075.     {
  1076.         return $this->showVariants;
  1077.     }
  1078.     /**
  1079.      * @return bool
  1080.      */
  1081.     public function getShowAppLoggerTab()
  1082.     {
  1083.         return $this->showAppLoggerTab;
  1084.     }
  1085.     /**
  1086.      * @param bool $showAppLoggerTab
  1087.      *
  1088.      * @return $this
  1089.      */
  1090.     public function setShowAppLoggerTab($showAppLoggerTab)
  1091.     {
  1092.         $this->showAppLoggerTab = (bool) $showAppLoggerTab;
  1093.         return $this;
  1094.     }
  1095.     /**
  1096.      * @return bool
  1097.      */
  1098.     public function getShowFieldLookup()
  1099.     {
  1100.         return $this->showFieldLookup;
  1101.     }
  1102.     /**
  1103.      * @param bool $showFieldLookup
  1104.      *
  1105.      * @return $this
  1106.      */
  1107.     public function setShowFieldLookup($showFieldLookup)
  1108.     {
  1109.         $this->showFieldLookup = (bool) $showFieldLookup;
  1110.         return $this;
  1111.     }
  1112.     /**
  1113.      * @return string
  1114.      */
  1115.     public function getLinkGeneratorReference()
  1116.     {
  1117.         return $this->linkGeneratorReference;
  1118.     }
  1119.     /**
  1120.      * @param string $linkGeneratorReference
  1121.      *
  1122.      * @return $this
  1123.      */
  1124.     public function setLinkGeneratorReference($linkGeneratorReference)
  1125.     {
  1126.         $this->linkGeneratorReference $linkGeneratorReference;
  1127.         return $this;
  1128.     }
  1129.     /**
  1130.      * @return DataObject\ClassDefinition\LinkGeneratorInterface|null
  1131.      */
  1132.     public function getLinkGenerator()
  1133.     {
  1134.         return DataObject\ClassDefinition\Helper\LinkGeneratorResolver::resolveGenerator($this->getLinkGeneratorReference());
  1135.     }
  1136.     /**
  1137.      * @return string|null
  1138.      */
  1139.     public function getPreviewGeneratorReference(): ?string
  1140.     {
  1141.         return $this->previewGeneratorReference;
  1142.     }
  1143.     /**
  1144.      * @param string|null $previewGeneratorReference
  1145.      */
  1146.     public function setPreviewGeneratorReference(?string $previewGeneratorReference): void
  1147.     {
  1148.         $this->previewGeneratorReference $previewGeneratorReference;
  1149.     }
  1150.     /**
  1151.      * @return DataObject\ClassDefinition\PreviewGeneratorInterface|null
  1152.      */
  1153.     public function getPreviewGenerator()
  1154.     {
  1155.         return DataObject\ClassDefinition\Helper\PreviewGeneratorResolver::resolveGenerator($this->getPreviewGeneratorReference());
  1156.     }
  1157.     /**
  1158.      * @return bool
  1159.      */
  1160.     public function isEnableGridLocking(): bool
  1161.     {
  1162.         return $this->enableGridLocking;
  1163.     }
  1164.     /**
  1165.      * @param bool $enableGridLocking
  1166.      */
  1167.     public function setEnableGridLocking(bool $enableGridLocking): void
  1168.     {
  1169.         $this->enableGridLocking $enableGridLocking;
  1170.     }
  1171.     /**
  1172.      * @return string|null
  1173.      */
  1174.     public function getImplementsInterfaces(): ?string
  1175.     {
  1176.         return $this->implementsInterfaces;
  1177.     }
  1178.     /**
  1179.      * @param string|null $implementsInterfaces
  1180.      *
  1181.      * @return $this
  1182.      */
  1183.     public function setImplementsInterfaces(?string $implementsInterfaces)
  1184.     {
  1185.         $this->implementsInterfaces $implementsInterfaces;
  1186.         return $this;
  1187.     }
  1188.     /**
  1189.      * @return array
  1190.      */
  1191.     public function getCompositeIndices(): array
  1192.     {
  1193.         return $this->compositeIndices;
  1194.     }
  1195.     /**
  1196.      * @param array|null $compositeIndices
  1197.      *
  1198.      * @return $this
  1199.      */
  1200.     public function setCompositeIndices($compositeIndices)
  1201.     {
  1202.         $this->compositeIndices $compositeIndices ?? [];
  1203.         return $this;
  1204.     }
  1205.     /**
  1206.      * @return bool
  1207.      */
  1208.     public function getGenerateTypeDeclarations()
  1209.     {
  1210.         return (bool) $this->generateTypeDeclarations;
  1211.     }
  1212.     /**
  1213.      * @param bool $generateTypeDeclarations
  1214.      *
  1215.      * @return $this
  1216.      */
  1217.     public function setGenerateTypeDeclarations($generateTypeDeclarations)
  1218.     {
  1219.         $this->generateTypeDeclarations = (bool) $generateTypeDeclarations;
  1220.         return $this;
  1221.     }
  1222.     /**
  1223.      * @return ClassDefinition\Data[]
  1224.      */
  1225.     public function getDeletedDataComponents()
  1226.     {
  1227.         return $this->deletedDataComponents;
  1228.     }
  1229.     /**
  1230.      * @param ClassDefinition\Data[] $deletedDataComponents
  1231.      *
  1232.      * @return $this
  1233.      */
  1234.     public function setDeletedDataComponents(array $deletedDataComponents): ClassDefinition
  1235.     {
  1236.         $this->deletedDataComponents $deletedDataComponents;
  1237.         return $this;
  1238.     }
  1239.     private function deleteDeletedDataComponentsInCustomLayout(): void
  1240.     {
  1241.         if (empty($this->getDeletedDataComponents())) {
  1242.             return;
  1243.         }
  1244.         $customLayouts = new ClassDefinition\CustomLayout\Listing();
  1245.         $customLayouts->setCondition('classId = ?'$this->getId());
  1246.         $customLayouts $customLayouts->load();
  1247.         foreach ($customLayouts as $customLayout) {
  1248.             $layoutDefinition $customLayout->getLayoutDefinitions();
  1249.             $this->deleteDeletedDataComponentsInLayoutDefinition($layoutDefinition);
  1250.             $customLayout->setLayoutDefinitions($layoutDefinition);
  1251.             $customLayout->save();
  1252.         }
  1253.     }
  1254.     private function deleteDeletedDataComponentsInLayoutDefinition(ClassDefinition\Layout $layoutDefinition): void
  1255.     {
  1256.         $componentsToDelete $this->getDeletedDataComponents();
  1257.         $componentDeleted false;
  1258.         $children = &$layoutDefinition->getChildrenByRef();
  1259.         $count count($children);
  1260.         for ($i 0$i $count$i++) {
  1261.             $component $children[$i];
  1262.             if (in_array($component$componentsToDelete)) {
  1263.                 unset($children[$i]);
  1264.                 $componentDeleted true;
  1265.             }
  1266.             if ($component instanceof ClassDefinition\Layout) {
  1267.                 $this->deleteDeletedDataComponentsInLayoutDefinition($component);
  1268.             }
  1269.         }
  1270.         if ($componentDeleted) {
  1271.             $children array_values($children);
  1272.         }
  1273.     }
  1274. }