vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/Multiselect.php line 25

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\Model;
  16. use Pimcore\Model\DataObject;
  17. use Pimcore\Model\DataObject\ClassDefinition\Data;
  18. use Pimcore\Model\DataObject\ClassDefinition\Service;
  19. use Pimcore\Model\DataObject\Concrete;
  20. use Pimcore\Normalizer\NormalizerInterface;
  21. class Multiselect extends Data implements
  22.     ResourcePersistenceAwareInterface,
  23.     QueryResourcePersistenceAwareInterface,
  24.     TypeDeclarationSupportInterface,
  25.     EqualComparisonInterface,
  26.     VarExporterInterface,
  27.     \JsonSerializable,
  28.     NormalizerInterface,
  29.     LayoutDefinitionEnrichmentInterface,
  30.     FieldDefinitionEnrichmentInterface,
  31.     DataContainerAwareInterface
  32. {
  33.     use DataObject\Traits\SimpleComparisonTrait;
  34.     use Extension\ColumnType;
  35.     use Extension\QueryColumnType;
  36.     use DataObject\Traits\SimpleNormalizerTrait;
  37.     /**
  38.      * Static type of this element
  39.      *
  40.      * @internal
  41.      *
  42.      * @var string
  43.      */
  44.     public $fieldtype 'multiselect';
  45.     /**
  46.      * Available options to select
  47.      *
  48.      * @internal
  49.      *
  50.      * @var array|null
  51.      */
  52.     public $options;
  53.     /**
  54.      * @internal
  55.      *
  56.      * @var string|int
  57.      */
  58.     public $width 0;
  59.     /**
  60.      * @internal
  61.      *
  62.      * @var int
  63.      */
  64.     public $height 0;
  65.     /**
  66.      * @internal
  67.      *
  68.      * @var int
  69.      */
  70.     public $maxItems;
  71.     /**
  72.      * @internal
  73.      *
  74.      * @var string
  75.      */
  76.     public $renderType;
  77.     /**
  78.      * Options provider class
  79.      *
  80.      * @internal
  81.      *
  82.      * @var string
  83.      */
  84.     public $optionsProviderClass;
  85.     /**
  86.      * Options provider data
  87.      *
  88.      * @internal
  89.      *
  90.      * @var string
  91.      */
  92.     public $optionsProviderData;
  93.     /**
  94.      * Type for the column to query
  95.      *
  96.      * @internal
  97.      *
  98.      * @var string
  99.      */
  100.     public $queryColumnType 'text';
  101.     /**
  102.      * Type for the column
  103.      *
  104.      * @internal
  105.      *
  106.      * @var string
  107.      */
  108.     public $columnType 'text';
  109.     /**
  110.      * @internal
  111.      *
  112.      * @var bool
  113.      */
  114.     public $dynamicOptions false;
  115.     /**
  116.      * @return array
  117.      */
  118.     public function getOptions()
  119.     {
  120.         return $this->options;
  121.     }
  122.     /**
  123.      * @param array $options
  124.      *
  125.      * @return $this
  126.      */
  127.     public function setOptions($options)
  128.     {
  129.         $this->options $options;
  130.         return $this;
  131.     }
  132.     /**
  133.      * @return string|int
  134.      */
  135.     public function getWidth()
  136.     {
  137.         return $this->width;
  138.     }
  139.     /**
  140.      * @param string|int $width
  141.      *
  142.      * @return $this
  143.      */
  144.     public function setWidth($width)
  145.     {
  146.         if (is_numeric($width)) {
  147.             $width = (int)$width;
  148.         }
  149.         $this->width $width;
  150.         return $this;
  151.     }
  152.     /**
  153.      * @return string|int
  154.      */
  155.     public function getHeight()
  156.     {
  157.         return $this->height;
  158.     }
  159.     /**
  160.      * @param string|int $height
  161.      *
  162.      * @return $this
  163.      */
  164.     public function setHeight($height)
  165.     {
  166.         if (is_numeric($height)) {
  167.             $height = (int)$height;
  168.         }
  169.         $this->height $height;
  170.         return $this;
  171.     }
  172.     /**
  173.      * @param int|string|null $maxItems
  174.      *
  175.      * @return $this
  176.      */
  177.     public function setMaxItems($maxItems)
  178.     {
  179.         $this->maxItems $this->getAsIntegerCast($maxItems);
  180.         return $this;
  181.     }
  182.     /**
  183.      * @return int
  184.      */
  185.     public function getMaxItems()
  186.     {
  187.         return $this->maxItems;
  188.     }
  189.     /**
  190.      * @param string|null $renderType
  191.      *
  192.      * @return $this
  193.      */
  194.     public function setRenderType($renderType)
  195.     {
  196.         $this->renderType $renderType;
  197.         return $this;
  198.     }
  199.     /**
  200.      * @return string
  201.      */
  202.     public function getRenderType()
  203.     {
  204.         return $this->renderType;
  205.     }
  206.     /**
  207.      * @see ResourcePersistenceAwareInterface::getDataForResource
  208.      *
  209.      * @param array|null $data
  210.      * @param null|DataObject\Concrete $object
  211.      * @param mixed $params
  212.      *
  213.      * @return string|null
  214.      */
  215.     public function getDataForResource($data$object null$params = [])
  216.     {
  217.         if (is_array($data)) {
  218.             return implode(','$data);
  219.         }
  220.         return null;
  221.     }
  222.     /**
  223.      * @see ResourcePersistenceAwareInterface::getDataFromResource
  224.      *
  225.      * @param string $data
  226.      * @param null|DataObject\Concrete $object
  227.      * @param mixed $params
  228.      *
  229.      * @return array|null
  230.      */
  231.     public function getDataFromResource($data$object null$params = [])
  232.     {
  233.         if (strlen($data)) {
  234.             return explode(','$data);
  235.         }
  236.         return null;
  237.     }
  238.     /**
  239.      * @see QueryResourcePersistenceAwareInterface::getDataForQueryResource
  240.      *
  241.      * @param array $data
  242.      * @param null|DataObject\Concrete $object
  243.      * @param mixed $params
  244.      *
  245.      * @return string|null
  246.      */
  247.     public function getDataForQueryResource($data$object null$params = [])
  248.     {
  249.         if (!empty($data) && is_array($data)) {
  250.             return ','.implode(','$data).',';
  251.         }
  252.         return null;
  253.     }
  254.     /**
  255.      * @see Data::getDataForEditmode
  256.      *
  257.      * @param array|null $data
  258.      * @param null|DataObject\Concrete $object
  259.      * @param mixed $params
  260.      *
  261.      * @return string|null
  262.      */
  263.     public function getDataForEditmode($data$object null$params = [])
  264.     {
  265.         if (is_array($data)) {
  266.             return implode(','$data);
  267.         }
  268.         return null;
  269.     }
  270.     /**
  271.      * @param array $data
  272.      * @param null|DataObject\Concrete $object
  273.      * @param mixed $params
  274.      *
  275.      * @return string
  276.      */
  277.     public function getDataForGrid($data$object null$params = [])
  278.     {
  279.         return $this->getDataForEditmode($data$object$params);
  280.     }
  281.     /**
  282.      * @see Data::getDataFromEditmode
  283.      *
  284.      * @param string $data
  285.      * @param null|DataObject\Concrete $object
  286.      * @param mixed $params
  287.      *
  288.      * @return string
  289.      */
  290.     public function getDataFromEditmode($data$object null$params = [])
  291.     {
  292.         return $data;
  293.     }
  294.     /**
  295.      * @see Data::getVersionPreview
  296.      *
  297.      * @param array|null $data
  298.      * @param null|DataObject\Concrete $object
  299.      * @param mixed $params
  300.      *
  301.      * @return string|null
  302.      */
  303.     public function getVersionPreview($data$object null$params = [])
  304.     {
  305.         if (is_array($data)) {
  306.             return implode(','array_map(function ($v) {
  307.                 return htmlspecialchars($vENT_QUOTES'UTF-8');
  308.             }, $data));
  309.         }
  310.         return null;
  311.     }
  312.     /**
  313.      * {@inheritdoc}
  314.      */
  315.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  316.     {
  317.         if (!$omitMandatoryCheck && $this->getMandatory() && empty($data)) {
  318.             throw new Model\Element\ValidationException('Empty mandatory field [ '.$this->getName().' ]');
  319.         }
  320.         if (!is_array($data) && !empty($data)) {
  321.             throw new Model\Element\ValidationException('Invalid multiselect data');
  322.         }
  323.     }
  324.     /**
  325.      * {@inheritdoc}
  326.      */
  327.     public function getForCsvExport($object$params = [])
  328.     {
  329.         $data $this->getDataFromObjectParam($object$params);
  330.         if (is_array($data)) {
  331.             return implode(','$data);
  332.         }
  333.         return '';
  334.     }
  335.     /**
  336.      * {@inheritdoc}
  337.      */
  338.     public function getDataForSearchIndex($object$params = [])
  339.     {
  340.         $data $this->getDataFromObjectParam($object$params);
  341.         if (is_array($data)) {
  342.             return implode(' '$data);
  343.         }
  344.         return '';
  345.     }
  346.     /**
  347.      * returns sql query statement to filter according to this data types value(s)
  348.      *
  349.      * @param  string $value
  350.      * @param  string $operator
  351.      * @param  array $params
  352.      *
  353.      * @return string
  354.      */
  355.     public function getFilterCondition($value$operator$params = [])
  356.     {
  357.         $params['name'] = $this->name;
  358.         return $this->getFilterConditionExt(
  359.             $value,
  360.             $operator,
  361.             $params
  362.         );
  363.     }
  364.     /**
  365.      * returns sql query statement to filter according to this data types value(s)
  366.      *
  367.      * @param string $value
  368.      * @param string $operator
  369.      * @param array $params optional params used to change the behavior
  370.      *
  371.      * @return string|null
  372.      */
  373.     public function getFilterConditionExt($value$operator$params = [])
  374.     {
  375.         if ($operator === '=') {
  376.             $name $params['name'] ? $params['name'] : $this->name;
  377.             $db \Pimcore\Db::get();
  378.             $key $db->quoteIdentifier($name);
  379.             if (!empty($params['brickPrefix'])) {
  380.                 $key $params['brickPrefix'].$key;
  381.             }
  382.             $value "'%,".$value.",%'";
  383.             return $key.' LIKE '.$value.' ';
  384.         }
  385.         return null;
  386.     }
  387.     /**
  388.      * {@inheritdoc}
  389.      */
  390.     public function isDiffChangeAllowed($object$params = [])
  391.     {
  392.         return true;
  393.     }
  394.     /** Generates a pretty version preview (similar to getVersionPreview) can be either html or
  395.      * a image URL. See the https://github.com/pimcore/object-merger bundle documentation for details
  396.      *
  397.      * @param array|null $data
  398.      * @param DataObject\Concrete|null $object
  399.      * @param mixed $params
  400.      *
  401.      * @return array|string
  402.      */
  403.     public function getDiffVersionPreview($data$object null$params = [])
  404.     {
  405.         if ($data) {
  406.             $map = [];
  407.             foreach ($data as $value) {
  408.                 $map[$value] = $value;
  409.             }
  410.             $html '<ul>';
  411.             foreach ($this->options as $option) {
  412.                 if ($map[$option['value']] ?? false) {
  413.                     $value $option['key'];
  414.                     $html .= '<li>' $value '</li>';
  415.                 }
  416.             }
  417.             $html .= '</ul>';
  418.             $value = [];
  419.             $value['html'] = $html;
  420.             $value['type'] = 'html';
  421.             return $value;
  422.         } else {
  423.             return '';
  424.         }
  425.     }
  426.     /**
  427.      * @param DataObject\ClassDefinition\Data\Multiselect $masterDefinition
  428.      */
  429.     public function synchronizeWithMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
  430.     {
  431.         $this->maxItems $masterDefinition->maxItems;
  432.         $this->options $masterDefinition->options;
  433.     }
  434.     /**
  435.      * @return string
  436.      */
  437.     public function getOptionsProviderClass()
  438.     {
  439.         return $this->optionsProviderClass;
  440.     }
  441.     /**
  442.      * @param string $optionsProviderClass
  443.      */
  444.     public function setOptionsProviderClass($optionsProviderClass)
  445.     {
  446.         $this->optionsProviderClass $optionsProviderClass;
  447.     }
  448.     /**
  449.      * @return string
  450.      */
  451.     public function getOptionsProviderData()
  452.     {
  453.         return $this->optionsProviderData;
  454.     }
  455.     /**
  456.      * @param string $optionsProviderData
  457.      */
  458.     public function setOptionsProviderData($optionsProviderData)
  459.     {
  460.         $this->optionsProviderData $optionsProviderData;
  461.     }
  462.     /**
  463.      * { @inheritdoc }
  464.      */
  465.     public function enrichFieldDefinition(/** array */ $context = []) /** : Data */
  466.     {
  467.         $optionsProvider DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider(
  468.             $this->getOptionsProviderClass(),
  469.                 DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT
  470.         );
  471.         if ($optionsProvider) {
  472.             $context['fieldname'] = $this->getName();
  473.             $options $optionsProvider->{'getOptions'}($context$this);
  474.             $this->setOptions($options);
  475.         }
  476.         return $this;
  477.     }
  478.     /**
  479.      * {@inheritdoc}
  480.      */
  481.     public function enrichLayoutDefinition(/*?Concrete */ $object/**  array */ $context = []) // : self
  482.     {
  483.         $optionsProvider DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider(
  484.             $this->getOptionsProviderClass(),
  485.             DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT
  486.         );
  487.         if ($optionsProvider) {
  488.             $context['object'] = $object;
  489.             if ($object) {
  490.                 $context['class'] = $object->getClass();
  491.             }
  492.             $context['fieldname'] = $this->getName();
  493.             $inheritanceEnabled DataObject::getGetInheritedValues();
  494.             DataObject::setGetInheritedValues(true);
  495.             $options $optionsProvider->{'getOptions'}($context$this);
  496.             DataObject::setGetInheritedValues($inheritanceEnabled);
  497.             $this->setOptions($options);
  498.             $hasStaticOptions $optionsProvider->{'hasStaticOptions'}($context$this);
  499.             $this->dynamicOptions = !$hasStaticOptions;
  500.         }
  501.         return $this;
  502.     }
  503.     /**
  504.      * @param array|null $existingData
  505.      * @param array $additionalData
  506.      *
  507.      * @return mixed
  508.      */
  509.     public function appendData($existingData$additionalData)
  510.     {
  511.         if (!is_array($existingData)) {
  512.             $existingData = [];
  513.         }
  514.         $existingData array_unique(array_merge($existingData$additionalData));
  515.         return $existingData;
  516.     }
  517.     /**
  518.      * @param array|null $existingData
  519.      * @param array $removeData
  520.      *
  521.      * @return array
  522.      */
  523.     public function removeData($existingData$removeData)
  524.     {
  525.         if (!is_array($existingData)) {
  526.             $existingData = [];
  527.         }
  528.         $existingData array_unique(array_diff($existingData$removeData));
  529.         return $existingData;
  530.     }
  531.     /**
  532.      * {@inheritdoc}
  533.      */
  534.     public function isFilterable(): bool
  535.     {
  536.         return true;
  537.     }
  538.     /**
  539.      * @param array|null $value1
  540.      * @param array|null $value2
  541.      *
  542.      * @return bool
  543.      */
  544.     public function isEqual($value1$value2): bool
  545.     {
  546.         return $this->isEqualArray($value1$value2);
  547.     }
  548.     /**
  549.      * @return $this
  550.      */
  551.     public function jsonSerialize()
  552.     {
  553.         if ($this->getOptionsProviderClass() && Service::doRemoveDynamicOptions()) {
  554.             $this->options null;
  555.         }
  556.         return $this;
  557.     }
  558.     /**
  559.      * {@inheritdoc}
  560.      */
  561.     public function resolveBlockedVars(): array
  562.     {
  563.         $blockedVars parent::resolveBlockedVars();
  564.         if ($this->getOptionsProviderClass()) {
  565.             $blockedVars[] = 'options';
  566.         }
  567.         return $blockedVars;
  568.     }
  569.     /**
  570.      * {@inheritdoc}
  571.      */
  572.     public function getParameterTypeDeclaration(): ?string
  573.     {
  574.         return '?array';
  575.     }
  576.     /**
  577.      * {@inheritdoc}
  578.      */
  579.     public function getReturnTypeDeclaration(): ?string
  580.     {
  581.         return '?array';
  582.     }
  583.     /**
  584.      * {@inheritdoc}
  585.      */
  586.     public function getPhpdocInputType(): ?string
  587.     {
  588.         return 'array|null';
  589.     }
  590.     /**
  591.      * {@inheritdoc}
  592.      */
  593.     public function getPhpdocReturnType(): ?string
  594.     {
  595.         return 'array|null';
  596.     }
  597.     /**
  598.      * Perform sanity checks, see #5010.
  599.      *
  600.      * @param mixed $containerDefinition
  601.      * @param array $params
  602.      *
  603.      * @return mixed
  604.      */
  605.     public function preSave($containerDefinition$params = [])
  606.     {
  607.         /** @var ?DataObject\ClassDefinition\DynamicOptionsProvider\MultiSelectOptionsProviderInterface $optionsProvider */
  608.         $optionsProvider DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider(
  609.             $this->getOptionsProviderClass(),
  610.             DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_MULTISELECT
  611.         );
  612.         if ($optionsProvider) {
  613.             $context = [];
  614.             $context['fieldname'] = $this->getName();
  615.             try {
  616.                 $options $optionsProvider->getOptions($context$this);
  617.             } catch (\Throwable $e) {
  618.                 // error from getOptions => no values => no comma => no problems
  619.                 $options null;
  620.             }
  621.         } else {
  622.             $options $this->getOptions();
  623.         }
  624.         if (is_array($options) && array_reduce($options, static function ($containsComma$option) {
  625.             return $containsComma || str_contains($option['value'], ',');
  626.         }, false)) {
  627.             throw new \Exception("Field {$this->getName()}: Multiselect option values may not contain commas (,) for now, see <a href='https://github.com/pimcore/pimcore/issues/5010' target='_blank'>issue #5010</a>.");
  628.         }
  629.     }
  630.     /**
  631.      * @param mixed $containerDefinition
  632.      * @param array $params
  633.      *
  634.      * @return mixed
  635.      */
  636.     public function postSave($containerDefinition$params = [])
  637.     {
  638.         // nothing to do
  639.     }
  640. }