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

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