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

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