vendor/pimcore/pimcore/models/DataObject/Fieldcollection/Definition.php line 117

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\Fieldcollection;
  15. use Pimcore\Cache\RuntimeCache;
  16. use Pimcore\DataObject\ClassBuilder\FieldDefinitionDocBlockBuilderInterface;
  17. use Pimcore\DataObject\ClassBuilder\PHPFieldCollectionClassDumperInterface;
  18. use Pimcore\Model;
  19. use Pimcore\Model\DataObject;
  20. use Pimcore\Model\DataObject\ClassDefinition\Data\FieldDefinitionEnrichmentInterface;
  21. /**
  22.  * @method \Pimcore\Model\DataObject\Fieldcollection\Definition\Dao getDao()
  23.  * @method string getTableName(DataObject\ClassDefinition $class)
  24.  * @method void createUpdateTable(DataObject\ClassDefinition $class)
  25.  * @method string getLocalizedTableName(DataObject\ClassDefinition $class)
  26.  */
  27. class Definition extends Model\AbstractModel
  28. {
  29.     use DataObject\Traits\FieldcollectionObjectbrickDefinitionTrait;
  30.     use DataObject\Traits\LocateFileTrait;
  31.     use Model\DataObject\ClassDefinition\Helper\VarExport;
  32.     /**
  33.      * @var array
  34.      */
  35.     protected const FORBIDDEN_NAMES = [
  36.         'abstract''class''data''folder''list''permissions''resource''dao''concrete''items',
  37.         'object''interface''default',
  38.     ];
  39.     /**
  40.      * {@inheritdoc}
  41.      */
  42.     protected function doEnrichFieldDefinition($fieldDefinition$context = [])
  43.     {
  44.         //TODO Pimcore 11: remove method_exists BC layer
  45.         if ($fieldDefinition instanceof FieldDefinitionEnrichmentInterface || method_exists($fieldDefinition'enrichFieldDefinition')) {
  46.             if (!$fieldDefinition instanceof FieldDefinitionEnrichmentInterface) {
  47.                 trigger_deprecation('pimcore/pimcore''10.1',
  48.                     sprintf('Usage of method_exists is deprecated since version 10.1 and will be removed in Pimcore 11.' .
  49.                     'Implement the %s interface instead.'FieldDefinitionEnrichmentInterface::class));
  50.             }
  51.             $context['containerType'] = 'fieldcollection';
  52.             $context['containerKey'] = $this->getKey();
  53.             $fieldDefinition $fieldDefinition->enrichFieldDefinition($context);
  54.         }
  55.         return $fieldDefinition;
  56.     }
  57.     /**
  58.      * @internal
  59.      *
  60.      * @param DataObject\ClassDefinition\Layout|DataObject\ClassDefinition\Data $def
  61.      */
  62.     protected function extractDataDefinitions($def)
  63.     {
  64.         if ($def instanceof DataObject\ClassDefinition\Layout) {
  65.             if ($def->hasChildren()) {
  66.                 foreach ($def->getChildren() as $child) {
  67.                     $this->extractDataDefinitions($child);
  68.                 }
  69.             }
  70.         }
  71.         if ($def instanceof DataObject\ClassDefinition\Data) {
  72.             $existing $this->getFieldDefinition($def->getName());
  73.             if ($existing && method_exists($existing'addReferencedField')) {
  74.                 // this is especially for localized fields which get aggregated here into one field definition
  75.                 // in the case that there are more than one localized fields in the class definition
  76.                 // see also pimcore.object.edit.addToDataFields();
  77.                 $existing->addReferencedField($def);
  78.             } else {
  79.                 $this->addFieldDefinition($def->getName(), $def);
  80.             }
  81.         }
  82.     }
  83.     /**
  84.      * @param string $key
  85.      *
  86.      * @throws \Exception
  87.      *
  88.      * @return self|null
  89.      */
  90.     public static function getByKey($key)
  91.     {
  92.         /** @var Definition $fc */
  93.         $fc null;
  94.         $cacheKey 'fieldcollection_' $key;
  95.         try {
  96.             $fc RuntimeCache::get($cacheKey);
  97.             if (!$fc) {
  98.                 throw new \Exception('FieldCollection in registry is not valid');
  99.             }
  100.         } catch (\Exception $e) {
  101.             $def = new Definition();
  102.             $def->setKey($key);
  103.             $fieldFile $def->getDefinitionFile();
  104.             if (is_file($fieldFile)) {
  105.                 $fc = include $fieldFile;
  106.                 RuntimeCache::set($cacheKey$fc);
  107.             }
  108.         }
  109.         if ($fc) {
  110.             return $fc;
  111.         }
  112.         return null;
  113.     }
  114.     /**
  115.      * @param bool $saveDefinitionFile
  116.      *
  117.      * @throws \Exception
  118.      */
  119.     public function save($saveDefinitionFile true)
  120.     {
  121.         if (!$this->getKey()) {
  122.             throw new \Exception('A field-collection needs a key to be saved!');
  123.         }
  124.         if (!preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/'$this->getKey()) || $this->isForbiddenName()) {
  125.             throw new \Exception(sprintf('Invalid key for field-collection: %s'$this->getKey()));
  126.         }
  127.         if ($this->getParentClass() && !preg_match('/^[a-zA-Z_\x7f-\xff\\\][a-zA-Z0-9_\x7f-\xff\\\]*$/'$this->getParentClass())) {
  128.             throw new \Exception(sprintf('Invalid parentClass value for class definition: %s',
  129.                 $this->getParentClass()));
  130.         }
  131.         $fieldDefinitions $this->getFieldDefinitions();
  132.         foreach ($fieldDefinitions as $fd) {
  133.             if ($fd->isForbiddenName()) {
  134.                 throw new \Exception(sprintf('Forbidden name used for field definition: %s'$fd->getName()));
  135.             }
  136.             if ($fd instanceof DataObject\ClassDefinition\Data\DataContainerAwareInterface) {
  137.                 $fd->preSave($this);
  138.             }
  139.         }
  140.         $this->generateClassFiles($saveDefinitionFile);
  141.         // update classes
  142.         $classList = new DataObject\ClassDefinition\Listing();
  143.         $classes $classList->load();
  144.         if (is_array($classes)) {
  145.             foreach ($classes as $class) {
  146.                 foreach ($class->getFieldDefinitions() as $fieldDef) {
  147.                     if ($fieldDef instanceof DataObject\ClassDefinition\Data\Fieldcollections) {
  148.                         if (in_array($this->getKey(), $fieldDef->getAllowedTypes())) {
  149.                             $this->getDao()->createUpdateTable($class);
  150.                             break;
  151.                         }
  152.                     }
  153.                 }
  154.             }
  155.         }
  156.     }
  157.     /**
  158.      * @internal
  159.      *
  160.      * @param bool $generateDefinitionFile
  161.      *
  162.      * @throws \Exception
  163.      * @throws DataObject\Exception\DefinitionWriteException
  164.      */
  165.     protected function generateClassFiles($generateDefinitionFile true)
  166.     {
  167.         if ($generateDefinitionFile && !$this->isWritable()) {
  168.             throw new DataObject\Exception\DefinitionWriteException();
  169.         }
  170.         $definitionFile $this->getDefinitionFile();
  171.         if ($generateDefinitionFile) {
  172.             /** @var self $clone */
  173.             $clone DataObject\Service::cloneDefinition($this);
  174.             $clone->setDao(null);
  175.             unset($clone->fieldDefinitions);
  176.             DataObject\ClassDefinition::cleanupForExport($clone->layoutDefinitions);
  177.             $exportedClass var_export($clonetrue);
  178.             $data '<?php';
  179.             $data .= "\n\n";
  180.             $data .=  $this->getInfoDocBlock();
  181.             $data .= "\n\n";
  182.             $data .= 'return ' $exportedClass ";\n";
  183.             \Pimcore\File::put($definitionFile$data);
  184.         }
  185.         \Pimcore::getContainer()->get(PHPFieldCollectionClassDumperInterface::class)->dumpPHPClass($this);
  186.         $fieldDefinitions $this->getFieldDefinitions();
  187.         foreach ($fieldDefinitions as $fd) {
  188.             if ($fd instanceof DataObject\ClassDefinition\Data\DataContainerAwareInterface) {
  189.                 $fd->postSave($this);
  190.             }
  191.         }
  192.     }
  193.     public function delete()
  194.     {
  195.         @unlink($this->getDefinitionFile());
  196.         @unlink($this->getPhpClassFile());
  197.         // update classes
  198.         $classList = new DataObject\ClassDefinition\Listing();
  199.         $classes $classList->load();
  200.         if (is_array($classes)) {
  201.             foreach ($classes as $class) {
  202.                 foreach ($class->getFieldDefinitions() as $fieldDef) {
  203.                     if ($fieldDef instanceof DataObject\ClassDefinition\Data\Fieldcollections) {
  204.                         if (in_array($this->getKey(), $fieldDef->getAllowedTypes())) {
  205.                             $this->getDao()->delete($class);
  206.                             break;
  207.                         }
  208.                     }
  209.                 }
  210.             }
  211.         }
  212.     }
  213.     /**
  214.      * @internal
  215.      *
  216.      * @return bool
  217.      */
  218.     public function isWritable(): bool
  219.     {
  220.         return $_SERVER['PIMCORE_CLASS_DEFINITION_WRITABLE'] ?? !str_starts_with($this->getDefinitionFile(), PIMCORE_CUSTOM_CONFIGURATION_DIRECTORY);
  221.     }
  222.     /**
  223.      * @internal
  224.      *
  225.      * @param string|null $key
  226.      *
  227.      * @return string
  228.      */
  229.     public function getDefinitionFile($key null)
  230.     {
  231.         return $this->locateDefinitionFile($key ?? $this->getKey(), 'fieldcollections/%s.php');
  232.     }
  233.     /**
  234.      * @internal
  235.      *
  236.      * @return string
  237.      */
  238.     public function getPhpClassFile()
  239.     {
  240.         return $this->locateFile(ucfirst($this->getKey()), 'DataObject/Fieldcollection/Data/%s.php');
  241.     }
  242.     /**
  243.      * @internal
  244.      *
  245.      * @return string
  246.      */
  247.     protected function getInfoDocBlock(): string
  248.     {
  249.         $cd '/**' "\n";
  250.         $cd .= " * Fields Summary:\n";
  251.         $fieldDefinitionDocBlockBuilder \Pimcore::getContainer()->get(FieldDefinitionDocBlockBuilderInterface::class);
  252.         foreach ($this->getFieldDefinitions() as $fieldDefinition) {
  253.             $cd .= ' * ' str_replace("\n""\n * "trim($fieldDefinitionDocBlockBuilder->buildFieldDefinitionDocBlock($fieldDefinition))) . "\n";
  254.         }
  255.         $cd .= ' */';
  256.         return $cd;
  257.     }
  258.     public function isForbiddenName(): bool
  259.     {
  260.         return in_array($this->getKey(), self::FORBIDDEN_NAMES);
  261.     }
  262. }