vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/ManyToOneRelation.php line 473

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\ClassDefinition\Data;
  15. use Pimcore\Logger;
  16. use Pimcore\Model;
  17. use Pimcore\Model\Asset;
  18. use Pimcore\Model\DataObject;
  19. use Pimcore\Model\DataObject\ClassDefinition\Data\Relations\AbstractRelations;
  20. use Pimcore\Model\Document;
  21. use Pimcore\Model\Element;
  22. use Pimcore\Normalizer\NormalizerInterface;
  23. class ManyToOneRelation extends AbstractRelations implements QueryResourcePersistenceAwareInterfaceTypeDeclarationSupportInterfaceVarExporterInterfaceNormalizerInterfaceIdRewriterInterfacePreGetDataInterfacePreSetDataInterface
  24. {
  25.     use Model\DataObject\ClassDefinition\Data\Extension\Relation;
  26.     use Extension\QueryColumnType;
  27.     use DataObject\ClassDefinition\Data\Relations\AllowObjectRelationTrait;
  28.     use DataObject\ClassDefinition\Data\Relations\AllowAssetRelationTrait;
  29.     use DataObject\ClassDefinition\Data\Relations\AllowDocumentRelationTrait;
  30.     use DataObject\ClassDefinition\Data\Extension\RelationFilterConditionParser;
  31.     /**
  32.      * Static type of this element
  33.      *
  34.      * @internal
  35.      *
  36.      * @var string
  37.      */
  38.     public $fieldtype 'manyToOneRelation';
  39.     /**
  40.      * @internal
  41.      *
  42.      * @var string|int
  43.      */
  44.     public $width 0;
  45.     /**
  46.      * @internal
  47.      *
  48.      * @var string
  49.      */
  50.     public $assetUploadPath;
  51.     /**
  52.      * @internal
  53.      *
  54.      * @var bool
  55.      */
  56.     public $relationType true;
  57.     /**
  58.      * Type for the column to query
  59.      *
  60.      * @internal
  61.      *
  62.      * @var array
  63.      */
  64.     public $queryColumnType = [
  65.         'id' => 'int(11)',
  66.         'type' => "enum('document','asset','object')",
  67.     ];
  68.     /**
  69.      * @internal
  70.      *
  71.      * @var bool
  72.      */
  73.     public $objectsAllowed false;
  74.     /**
  75.      * @internal
  76.      *
  77.      * @var bool
  78.      */
  79.     public $assetsAllowed false;
  80.     /**
  81.      * Allowed asset types
  82.      *
  83.      * @internal
  84.      *
  85.      * @var array
  86.      */
  87.     public $assetTypes = [];
  88.     /**
  89.      * @internal
  90.      *
  91.      * @var bool
  92.      */
  93.     public $documentsAllowed false;
  94.     /**
  95.      * Allowed document types
  96.      *
  97.      * @internal
  98.      *
  99.      * @var array
  100.      */
  101.     public $documentTypes = [];
  102.     /**
  103.      * @return bool
  104.      */
  105.     public function getObjectsAllowed()
  106.     {
  107.         return $this->objectsAllowed;
  108.     }
  109.     /**
  110.      * @param bool $objectsAllowed
  111.      *
  112.      * @return $this
  113.      */
  114.     public function setObjectsAllowed($objectsAllowed)
  115.     {
  116.         $this->objectsAllowed $objectsAllowed;
  117.         return $this;
  118.     }
  119.     /**
  120.      * @return bool
  121.      */
  122.     public function getDocumentsAllowed()
  123.     {
  124.         return $this->documentsAllowed;
  125.     }
  126.     /**
  127.      * @param bool $documentsAllowed
  128.      *
  129.      * @return $this
  130.      */
  131.     public function setDocumentsAllowed($documentsAllowed)
  132.     {
  133.         $this->documentsAllowed $documentsAllowed;
  134.         return $this;
  135.     }
  136.     /**
  137.      * @return array
  138.      */
  139.     public function getDocumentTypes()
  140.     {
  141.         return $this->documentTypes ?: [];
  142.     }
  143.     /**
  144.      * @param array $documentTypes
  145.      *
  146.      * @return $this
  147.      */
  148.     public function setDocumentTypes($documentTypes)
  149.     {
  150.         $this->documentTypes Element\Service::fixAllowedTypes($documentTypes'documentTypes');
  151.         return $this;
  152.     }
  153.     /**
  154.      *
  155.      * @return bool
  156.      */
  157.     public function getAssetsAllowed()
  158.     {
  159.         return $this->assetsAllowed;
  160.     }
  161.     /**
  162.      *
  163.      * @param bool $assetsAllowed
  164.      *
  165.      * @return $this
  166.      */
  167.     public function setAssetsAllowed($assetsAllowed)
  168.     {
  169.         $this->assetsAllowed $assetsAllowed;
  170.         return $this;
  171.     }
  172.     /**
  173.      * @return array
  174.      */
  175.     public function getAssetTypes()
  176.     {
  177.         return $this->assetTypes ?: [];
  178.     }
  179.     /**
  180.      * @param array $assetTypes
  181.      *
  182.      * @return $this
  183.      */
  184.     public function setAssetTypes($assetTypes)
  185.     {
  186.         $this->assetTypes Element\Service::fixAllowedTypes($assetTypes'assetTypes');
  187.         return $this;
  188.     }
  189.     /**
  190.      * {@inheritdoc}
  191.      */
  192.     protected function prepareDataForPersistence($data$object null$params = [])
  193.     {
  194.         if ($data instanceof Element\ElementInterface) {
  195.             $type Element\Service::getElementType($data);
  196.             $id $data->getId();
  197.             return [[
  198.                 'dest_id' => $id,
  199.                 'type' => $type,
  200.                 'fieldname' => $this->getName(),
  201.             ]];
  202.         }
  203.         return null;
  204.     }
  205.     /**
  206.      * {@inheritdoc}
  207.      */
  208.     protected function loadData(array $data$object null$params = [])
  209.     {
  210.         // data from relation table
  211.         $data current($data);
  212.         $result = [
  213.             'dirty' => false,
  214.             'data' => null,
  215.         ];
  216.         if (!empty($data['dest_id']) && !empty($data['type'])) {
  217.             $element Element\Service::getElementById($data['type'], $data['dest_id']);
  218.             if ($element instanceof Element\ElementInterface) {
  219.                 $result['data'] = $element;
  220.             } else {
  221.                 $result['dirty'] = true;
  222.             }
  223.         }
  224.         return $result;
  225.     }
  226.     /**
  227.      * @see QueryResourcePersistenceAwareInterface::getDataForQueryResource
  228.      *
  229.      * @param Asset|Document|DataObject\AbstractObject $data
  230.      * @param null|DataObject\Concrete $object
  231.      * @param mixed $params
  232.      *
  233.      * @return array
  234.      */
  235.     public function getDataForQueryResource($data$object null$params = [])
  236.     {
  237.         $rData $this->prepareDataForPersistence($data$object$params);
  238.         $return = [];
  239.         $return[$this->getName() . '__id'] = isset($rData[0]['dest_id']) ? $rData[0]['dest_id'] : null;
  240.         $return[$this->getName() . '__type'] = isset($rData[0]['type']) ? $rData[0]['type'] : null;
  241.         return $return;
  242.     }
  243.     /**
  244.      * @see Data::getDataForEditmode
  245.      *
  246.      * @param Element\ElementInterface|null $data
  247.      * @param null|DataObject\Concrete $object
  248.      * @param array|null $params
  249.      *
  250.      * @return array|null
  251.      */
  252.     public function getDataForEditmode($data$object null$params = [])
  253.     {
  254.         if ($data instanceof Element\ElementInterface) {
  255.             $r = [
  256.                 'id' => $data->getId(),
  257.                 'path' => $data->getRealFullPath(),
  258.                 'subtype' => $data->getType(),
  259.                 'type' => Element\Service::getElementType($data),
  260.                 'published' => Element\Service::isPublished($data),
  261.             ];
  262.             return $r;
  263.         }
  264.         return null;
  265.     }
  266.     /**
  267.      * @see Data::getDataFromEditmode
  268.      *
  269.      * @param array $data
  270.      * @param null|DataObject\Concrete $object
  271.      * @param mixed $params
  272.      *
  273.      * @return Asset|Document|DataObject\AbstractObject|null
  274.      */
  275.     public function getDataFromEditmode($data$object null$params = [])
  276.     {
  277.         if (!empty($data['id']) && !empty($data['type'])) {
  278.             return Element\Service::getElementById($data['type'], $data['id']);
  279.         }
  280.         return null;
  281.     }
  282.     /**
  283.      * @param array $data
  284.      * @param null|DataObject\Concrete $object
  285.      * @param mixed $params
  286.      *
  287.      * @return Asset|Document|DataObject\AbstractObject
  288.      */
  289.     public function getDataFromGridEditor($data$object null$params = [])
  290.     {
  291.         return $this->getDataFromEditmode($data$object$params);
  292.     }
  293.     /**
  294.      * @param Element\ElementInterface|null $data
  295.      * @param DataObject\Concrete $object
  296.      * @param array $params
  297.      *
  298.      * @return array|null
  299.      */
  300.     public function getDataForGrid($data$object null$params = [])
  301.     {
  302.         return $this->getDataForEditmode($data$object$params);
  303.     }
  304.     /**
  305.      * @see Data::getVersionPreview
  306.      *
  307.      * @param Element\ElementInterface|null $data
  308.      * @param null|DataObject\Concrete $object
  309.      * @param mixed $params
  310.      *
  311.      * @return string
  312.      */
  313.     public function getVersionPreview($data$object null$params = [])
  314.     {
  315.         if ($data instanceof Element\ElementInterface) {
  316.             return Element\Service::getElementType($data).' '.$data->getRealFullPath();
  317.         }
  318.         return '';
  319.     }
  320.     /**
  321.      * @return string|int
  322.      */
  323.     public function getWidth()
  324.     {
  325.         return $this->width;
  326.     }
  327.     /**
  328.      * @param string|int $width
  329.      *
  330.      * @return $this
  331.      */
  332.     public function setWidth($width)
  333.     {
  334.         if (is_numeric($width)) {
  335.             $width = (int)$width;
  336.         }
  337.         $this->width $width;
  338.         return $this;
  339.     }
  340.     /**
  341.      * {@inheritdoc}
  342.      */
  343.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  344.     {
  345.         if (!$omitMandatoryCheck && $this->getMandatory() && empty($data)) {
  346.             throw new Element\ValidationException('Empty mandatory field [ '.$this->getName().' ]');
  347.         }
  348.         if ($data instanceof Document) {
  349.             $allow $this->allowDocumentRelation($data);
  350.         } elseif ($data instanceof Asset) {
  351.             $allow $this->allowAssetRelation($data);
  352.         } elseif ($data instanceof DataObject\AbstractObject) {
  353.             $allow $this->allowObjectRelation($data);
  354.         } elseif (empty($data)) {
  355.             $allow true;
  356.         } else {
  357.             Logger::error(sprintf('Invalid data in field `%s` [type: %s]'$this->getName(), $this->getFieldtype()));
  358.             $allow false;
  359.         }
  360.         if (!$allow) {
  361.             throw new Element\ValidationException(sprintf('Invalid data in field `%s` [type: %s]'$this->getName(), $this->getFieldtype()));
  362.         }
  363.     }
  364.     /**
  365.      * {@inheritdoc}
  366.      */
  367.     public function getForCsvExport($object$params = [])
  368.     {
  369.         $data $this->getDataFromObjectParam($object$params);
  370.         if ($data instanceof Element\ElementInterface) {
  371.             return Element\Service::getElementType($data).':'.$data->getRealFullPath();
  372.         }
  373.         return '';
  374.     }
  375.     /**
  376.      * @param Element\ElementInterface|null $data
  377.      *
  378.      * @return array
  379.      */
  380.     public function resolveDependencies($data)
  381.     {
  382.         $dependencies = [];
  383.         if ($data instanceof Element\ElementInterface) {
  384.             $elementType Element\Service::getElementType($data);
  385.             $dependencies[$elementType '_' $data->getId()] = [
  386.                 'id' => $data->getId(),
  387.                 'type' => $elementType,
  388.             ];
  389.         }
  390.         return $dependencies;
  391.     }
  392.     /**
  393.      * @param DataObject\Concrete|DataObject\Localizedfield|DataObject\Objectbrick\Data\AbstractData|DataObject\Fieldcollection\Data\AbstractData $container
  394.      * @param array $params
  395.      *
  396.      * @return null|Element\ElementInterface
  397.      */
  398.     public function preGetData(/** mixed */ $container/** array */ $params = []) // : mixed
  399.     {
  400.         $data null;
  401.         if ($container instanceof DataObject\Concrete) {
  402.             $data $container->getObjectVar($this->getName());
  403.             if (!$container->isLazyKeyLoaded($this->getName())) {
  404.                 $data $this->load($container);
  405.                 $container->setObjectVar($this->getName(), $data);
  406.                 $this->markLazyloadedFieldAsLoaded($container);
  407.             }
  408.         } elseif ($container instanceof DataObject\Localizedfield) {
  409.             $data $params['data'];
  410.         } elseif ($container instanceof DataObject\Fieldcollection\Data\AbstractData) {
  411.             parent::loadLazyFieldcollectionField($container);
  412.             $data $container->getObjectVar($this->getName());
  413.         } elseif ($container instanceof DataObject\Objectbrick\Data\AbstractData) {
  414.             parent::loadLazyBrickField($container);
  415.             $data $container->getObjectVar($this->getName());
  416.         }
  417.         if (DataObject::doHideUnpublished() && ($data instanceof Element\ElementInterface)) {
  418.             if (!Element\Service::isPublished($data)) {
  419.                 return null;
  420.             }
  421.         }
  422.         return $data;
  423.     }
  424.     /**
  425.      * { @inheritdoc }
  426.      */
  427.     public function preSetData(/** mixed */ $container/**  mixed */ $data/** array */ $params = []) // : mixed
  428.     {
  429.         $this->markLazyloadedFieldAsLoaded($container);
  430.         return $data;
  431.     }
  432.     /**
  433.      * @param string $assetUploadPath
  434.      *
  435.      * @return $this
  436.      */
  437.     public function setAssetUploadPath($assetUploadPath)
  438.     {
  439.         $this->assetUploadPath $assetUploadPath;
  440.         return $this;
  441.     }
  442.     /**
  443.      * @return string
  444.      */
  445.     public function getAssetUploadPath()
  446.     {
  447.         return $this->assetUploadPath;
  448.     }
  449.     /**
  450.      * {@inheritdoc}
  451.      */
  452.     public function isDiffChangeAllowed($object$params = [])
  453.     {
  454.         return true;
  455.     }
  456.     /**
  457.      * { @inheritdoc }
  458.      */
  459.     public function rewriteIds(/** mixed */ $container/** array */ $idMapping/** array */ $params = []) /** :mixed */
  460.     {
  461.         $data $this->getDataFromObjectParam($container$params);
  462.         if ($data) {
  463.             $data $this->rewriteIdsService([$data], $idMapping);
  464.             $data $data[0]; //get the first element
  465.         }
  466.         return $data;
  467.     }
  468.     /**
  469.      * @param DataObject\ClassDefinition\Data\ManyToOneRelation $masterDefinition
  470.      */
  471.     public function synchronizeWithMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
  472.     {
  473.         $this->assetUploadPath $masterDefinition->assetUploadPath;
  474.         $this->relationType $masterDefinition->relationType;
  475.     }
  476.     /**
  477.      * {@inheritdoc}
  478.      */
  479.     protected function getPhpdocType()
  480.     {
  481.         return implode(' | '$this->getPhpDocClassString(false));
  482.     }
  483.     /**
  484.      * {@inheritdoc}
  485.      */
  486.     public function normalize($value$params = [])
  487.     {
  488.         if ($value) {
  489.             $type Element\Service::getElementType($value);
  490.             $id $value->getId();
  491.             return [
  492.                 'type' => $type,
  493.                 'id' => $id,
  494.             ];
  495.         }
  496.         return null;
  497.     }
  498.     /**
  499.      * {@inheritdoc}
  500.      */
  501.     public function denormalize($value$params = [])
  502.     {
  503.         if (is_array($value)) {
  504.             $type $value['type'];
  505.             $id $value['id'];
  506.             return Element\Service::getElementById($type$id);
  507.         }
  508.         return null;
  509.     }
  510.     /**
  511.      * @param Element\ElementInterface|null $value1
  512.      * @param Element\ElementInterface|null $value2
  513.      *
  514.      * @return bool
  515.      */
  516.     public function isEqual($value1$value2): bool
  517.     {
  518.         $value1 $value1 $value1->getType() . $value1->getId() : null;
  519.         $value2 $value2 $value2->getType() . $value2->getId() : null;
  520.         return $value1 === $value2;
  521.     }
  522.     /**
  523.      * {@inheritdoc}
  524.      */
  525.     public function isFilterable(): bool
  526.     {
  527.         return true;
  528.     }
  529.     /**
  530.      * {@inheritdoc}
  531.      */
  532.     public function getParameterTypeDeclaration(): ?string
  533.     {
  534.         return '?\\' Element\AbstractElement::class;
  535.     }
  536.     /**
  537.      * {@inheritdoc}
  538.      */
  539.     public function getReturnTypeDeclaration(): ?string
  540.     {
  541.         return '?\\' Element\AbstractElement::class;
  542.     }
  543.     /**
  544.      * {@inheritdoc}
  545.      */
  546.     public function addListingFilter(DataObject\Listing $listing$data$operator '=')
  547.     {
  548.         if ($data instanceof Element\ElementInterface) {
  549.             $data = [
  550.                 'id' => $data->getId(),
  551.                 'type' => Element\Service::getElementType($data),
  552.             ];
  553.         }
  554.         if (!isset($data['id'], $data['type'])) {
  555.             throw new \InvalidArgumentException('Please provide an array with keys "id" and "type" or an object which implements '.Element\ElementInterface::class);
  556.         }
  557.         if ($operator === '=') {
  558.             $listing->addConditionParam('`'.$this->getName().'__id` = ? AND `'.$this->getName().'__type` = ?', [$data['id'], $data['type']]);
  559.             return $listing;
  560.         }
  561.         throw new \InvalidArgumentException('Filtering '.__CLASS__.' does only support "=" operator');
  562.     }
  563.     /**
  564.      * {@inheritdoc}
  565.      */
  566.     public function getPhpdocInputType(): ?string
  567.     {
  568.         if ($phpdocType $this->getPhpdocType()) {
  569.             return $phpdocType '|null';
  570.         }
  571.         return null;
  572.     }
  573.     /**
  574.      * {@inheritdoc}
  575.      */
  576.     public function getPhpdocReturnType(): ?string
  577.     {
  578.         if ($phpdocType $this->getPhpdocType()) {
  579.             return $phpdocType '|null';
  580.         }
  581.         return null;
  582.     }
  583.     /**
  584.      * Filter by relation feature
  585.      *
  586.      * @param array|string|null $value
  587.      * @param string            $operator
  588.      * @param array             $params
  589.      *
  590.      * @return string
  591.      */
  592.     public function getFilterConditionExt($value$operator$params = [])
  593.     {
  594.         $name $params['name'] . '__id';
  595.         if (preg_match('/^(asset|object|document)\|(\d+)/'$value$matches)) {
  596.             $typeField $params['name'] . '__type';
  597.             $typeCondition '`' $typeField '` = ' "'" $matches[1] . "'";
  598.             $value $matches[2];
  599.             return '(' $typeCondition ' AND ' $this->getRelationFilterCondition($value$operator$name) . ')';
  600.         }
  601.         return $this->getRelationFilterCondition($value$operator$name);
  602.     }
  603. }