vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/ManyToManyObjectRelation.php line 448

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\Relations\AbstractRelations;
  18. use Pimcore\Model\DataObject\Concrete;
  19. use Pimcore\Model\Element;
  20. use Pimcore\Normalizer\NormalizerInterface;
  21. class ManyToManyObjectRelation extends AbstractRelations implements QueryResourcePersistenceAwareInterfaceOptimizedAdminLoadingInterfaceTypeDeclarationSupportInterfaceVarExporterInterfaceNormalizerInterfaceIdRewriterInterfacePreGetDataInterfacePreSetDataInterfaceLayoutDefinitionEnrichmentInterface
  22. {
  23.     use Model\DataObject\ClassDefinition\Data\Extension\Relation;
  24.     use Extension\QueryColumnType;
  25.     use DataObject\ClassDefinition\Data\Relations\AllowObjectRelationTrait;
  26.     use DataObject\ClassDefinition\Data\Relations\ManyToManyRelationTrait;
  27.     use DataObject\ClassDefinition\Data\Extension\RelationFilterConditionParser;
  28.     /**
  29.      * Static type of this element
  30.      *
  31.      * @internal
  32.      *
  33.      * @var string
  34.      */
  35.     public $fieldtype 'manyToManyObjectRelation';
  36.     /**
  37.      * @internal
  38.      *
  39.      * @var string|int
  40.      */
  41.     public $width 0;
  42.     /**
  43.      * Type for the column to query
  44.      *
  45.      * @internal
  46.      *
  47.      * @var string|int
  48.      */
  49.     public $height 0;
  50.     /**
  51.      * @internal
  52.      *
  53.      * @var int|null
  54.      */
  55.     public $maxItems;
  56.     /**
  57.      * Type for the column to query
  58.      *
  59.      * @internal
  60.      *
  61.      * @var string
  62.      */
  63.     public $queryColumnType 'text';
  64.     /**
  65.      * @internal
  66.      *
  67.      * @var bool
  68.      */
  69.     public $relationType true;
  70.     /**
  71.      * @internal
  72.      *
  73.      * @var string|null
  74.      */
  75.     public $visibleFields;
  76.     /**
  77.      * @internal
  78.      *
  79.      * @var bool
  80.      */
  81.     public $allowToCreateNewObject true;
  82.     /**
  83.      * @internal
  84.      *
  85.      * @var bool
  86.      */
  87.     public $optimizedAdminLoading false;
  88.     /**
  89.      * @internal
  90.      *
  91.      * @var bool
  92.      */
  93.     public $enableTextSelection false;
  94.     /**
  95.      * @internal
  96.      *
  97.      * @var array
  98.      */
  99.     public $visibleFieldDefinitions = [];
  100.     /**
  101.      * @return bool
  102.      */
  103.     public function getObjectsAllowed()
  104.     {
  105.         return true;
  106.     }
  107.     /**
  108.      * {@inheritdoc}
  109.      */
  110.     protected function prepareDataForPersistence($data$object null$params = [])
  111.     {
  112.         $return = [];
  113.         if (is_array($data) && count($data) > 0) {
  114.             $counter 1;
  115.             foreach ($data as $object) {
  116.                 if ($object instanceof DataObject\Concrete) {
  117.                     $return[] = [
  118.                         'dest_id' => $object->getId(),
  119.                         'type' => 'object',
  120.                         'fieldname' => $this->getName(),
  121.                         'index' => $counter,
  122.                     ];
  123.                 }
  124.                 $counter++;
  125.             }
  126.             return $return;
  127.         } elseif (is_array($data) && count($data) === 0) {
  128.             //give empty array if data was not null
  129.             return [];
  130.         } else {
  131.             //return null if data was null - this indicates data was not loaded
  132.             return null;
  133.         }
  134.     }
  135.     /**
  136.      * {@inheritdoc}
  137.      */
  138.     protected function loadData(array $data$object null$params = [])
  139.     {
  140.         $objects = [
  141.             'dirty' => false,
  142.             'data' => [],
  143.         ];
  144.         foreach ($data as $relation) {
  145.             $o DataObject::getById($relation['dest_id']);
  146.             if ($o instanceof DataObject\Concrete) {
  147.                 $objects['data'][] = $o;
  148.             } else {
  149.                 $objects['dirty'] = true;
  150.             }
  151.         }
  152.         //must return array - otherwise this means data is not loaded
  153.         return $objects;
  154.     }
  155.     /**
  156.      * @see QueryResourcePersistenceAwareInterface::getDataForQueryResource
  157.      *
  158.      * @param mixed $data
  159.      * @param null|DataObject\Concrete $object
  160.      * @param mixed $params
  161.      *
  162.      * @throws \Exception
  163.      *
  164.      * @return string|null
  165.      */
  166.     public function getDataForQueryResource($data$object null$params = [])
  167.     {
  168.         //return null when data is not set
  169.         if (!$data) {
  170.             return null;
  171.         }
  172.         $ids = [];
  173.         if (is_array($data)) {
  174.             foreach ($data as $relation) {
  175.                 if ($relation instanceof DataObject\Concrete) {
  176.                     $ids[] = $relation->getId();
  177.                 }
  178.             }
  179.             return ',' implode(','$ids) . ',';
  180.         }
  181.         throw new \Exception('invalid data passed to getDataForQueryResource - must be array and it is: ' print_r($datatrue));
  182.     }
  183.     /**
  184.      * @see Data::getDataForEditmode
  185.      *
  186.      * @param array $data
  187.      * @param null|DataObject\Concrete $object
  188.      * @param mixed $params
  189.      *
  190.      * @return array
  191.      */
  192.     public function getDataForEditmode($data$object null$params = [])
  193.     {
  194.         $return = [];
  195.         $visibleFieldsArray $this->getVisibleFields() ? explode(','$this->getVisibleFields()) : [];
  196.         $gridFields = (array)$visibleFieldsArray;
  197.         // add data
  198.         if (is_array($data) && count($data) > 0) {
  199.             foreach ($data as $referencedObject) {
  200.                 if ($referencedObject instanceof DataObject\Concrete) {
  201.                     $return[] = DataObject\Service::gridObjectData($referencedObject$gridFieldsnull, ['purpose' => 'editmode']);
  202.                 }
  203.             }
  204.         }
  205.         return $return;
  206.     }
  207.     /**
  208.      * @see Data::getDataFromEditmode
  209.      *
  210.      * @param array|null|false $data
  211.      * @param null|DataObject\Concrete $object
  212.      * @param mixed $params
  213.      *
  214.      * @return array|null
  215.      */
  216.     public function getDataFromEditmode($data$object null$params = [])
  217.     {
  218.         //if not set, return null
  219.         if ($data === null || $data === false) {
  220.             return null;
  221.         }
  222.         $objects = [];
  223.         if (is_array($data) && count($data) > 0) {
  224.             foreach ($data as $object) {
  225.                 $o DataObject::getById($object['id']);
  226.                 if ($o) {
  227.                     $objects[] = $o;
  228.                 }
  229.             }
  230.         }
  231.         //must return array if data shall be set
  232.         return $objects;
  233.     }
  234.     /**
  235.      * @see Data::getDataFromEditmode
  236.      *
  237.      * @param array $data
  238.      * @param null|DataObject\Concrete $object
  239.      * @param mixed $params
  240.      *
  241.      * @return array
  242.      */
  243.     public function getDataFromGridEditor($data$object null$params = [])
  244.     {
  245.         return $this->getDataFromEditmode($data$object$params);
  246.     }
  247.     /**
  248.      * @param array|null $data
  249.      * @param DataObject\Concrete|null $object
  250.      * @param mixed $params
  251.      *
  252.      * @return array|null
  253.      */
  254.     public function getDataForGrid($data$object null$params = [])
  255.     {
  256.         return $this->getDataForEditmode($data$object$params);
  257.     }
  258.     /**
  259.      * @see Data::getVersionPreview
  260.      *
  261.      * @param Element\ElementInterface[]|null $data
  262.      * @param null|DataObject\Concrete $object
  263.      * @param mixed $params
  264.      *
  265.      * @return string|null
  266.      */
  267.     public function getVersionPreview($data$object null$params = [])
  268.     {
  269.         if (is_array($data) && count($data) > 0) {
  270.             $paths = [];
  271.             foreach ($data as $o) {
  272.                 if ($o instanceof Element\ElementInterface) {
  273.                     $paths[] = $o->getRealFullPath();
  274.                 }
  275.             }
  276.             return implode('<br />'$paths);
  277.         }
  278.         return null;
  279.     }
  280.     /**
  281.      * @return string|int
  282.      */
  283.     public function getWidth()
  284.     {
  285.         return $this->width;
  286.     }
  287.     /**
  288.      * @param string|int $width
  289.      *
  290.      * @return $this
  291.      */
  292.     public function setWidth($width)
  293.     {
  294.         if (is_numeric($width)) {
  295.             $width = (int)$width;
  296.         }
  297.         $this->width $width;
  298.         return $this;
  299.     }
  300.     /**
  301.      * @return string|int
  302.      */
  303.     public function getHeight()
  304.     {
  305.         return $this->height;
  306.     }
  307.     /**
  308.      * @param string|int $height
  309.      *
  310.      * @return $this
  311.      */
  312.     public function setHeight($height)
  313.     {
  314.         if (is_numeric($height)) {
  315.             $height = (int)$height;
  316.         }
  317.         $this->height $height;
  318.         return $this;
  319.     }
  320.     /**
  321.      * {@inheritdoc}
  322.      */
  323.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  324.     {
  325.         if (!$omitMandatoryCheck && $this->getMandatory() && empty($data)) {
  326.             throw new Element\ValidationException('Empty mandatory field [ '.$this->getName().' ]');
  327.         }
  328.         if (is_array($data)) {
  329.             $this->performMultipleAssignmentCheck($data);
  330.             foreach ($data as $o) {
  331.                 if (empty($o)) {
  332.                     continue;
  333.                 }
  334.                 $allowClass $this->allowObjectRelation($o);
  335.                 if (!$allowClass || !($o instanceof DataObject\Concrete)) {
  336.                     if (!$allowClass && $o instanceof DataObject\Concrete) {
  337.                         $id $o->getId();
  338.                     } else {
  339.                         $id '??';
  340.                     }
  341.                     throw new Element\ValidationException('Invalid object relation to object ['.$id.'] in field ' $this->getName(). ' , tried to assign ' $o->getId());
  342.                 }
  343.             }
  344.             if ($this->getMaxItems() && count($data) > $this->getMaxItems()) {
  345.                 throw new Element\ValidationException('Number of allowed relations in field `' $this->getName() . '` exceeded (max. ' $this->getMaxItems() . ')');
  346.             }
  347.         }
  348.     }
  349.     /**
  350.      * {@inheritdoc}
  351.      */
  352.     public function getForCsvExport($object$params = [])
  353.     {
  354.         $data $this->getDataFromObjectParam($object$params);
  355.         if (is_array($data)) {
  356.             $paths = [];
  357.             foreach ($data as $eo) {
  358.                 if ($eo instanceof Element\ElementInterface) {
  359.                     $paths[] = $eo->getRealFullPath();
  360.                 }
  361.             }
  362.             return implode(','$paths);
  363.         }
  364.         return '';
  365.     }
  366.     /**
  367.      * @param DataObject\AbstractObject[]|null $data
  368.      *
  369.      * @return array
  370.      */
  371.     public function resolveDependencies($data)
  372.     {
  373.         $dependencies = [];
  374.         if (is_array($data) && count($data) > 0) {
  375.             foreach ($data as $o) {
  376.                 if ($o instanceof DataObject\AbstractObject) {
  377.                     $dependencies['object_' $o->getId()] = [
  378.                         'id' => $o->getId(),
  379.                         'type' => 'object',
  380.                     ];
  381.                 }
  382.             }
  383.         }
  384.         return $dependencies;
  385.     }
  386.     /**
  387.      * @param mixed $container
  388.      * @param array $params
  389.      *
  390.      * @return array
  391.      */
  392.     public function preGetData(/** mixed */ $container/** array */ $params = []) // : mixed
  393.     {
  394.         $data null;
  395.         if ($container instanceof DataObject\Concrete) {
  396.             $data $container->getObjectVar($this->getName());
  397.             if (!$container->isLazyKeyLoaded($this->getName())) {
  398.                 $data $this->load($container);
  399.                 $container->setObjectVar($this->getName(), $data);
  400.                 $this->markLazyloadedFieldAsLoaded($container);
  401.             }
  402.         } elseif ($container instanceof DataObject\Localizedfield) {
  403.             $data $params['data'];
  404.         } elseif ($container instanceof DataObject\Fieldcollection\Data\AbstractData) {
  405.             parent::loadLazyFieldcollectionField($container);
  406.             $data $container->getObjectVar($this->getName());
  407.         } elseif ($container instanceof DataObject\Objectbrick\Data\AbstractData) {
  408.             parent::loadLazyBrickField($container);
  409.             $data $container->getObjectVar($this->getName());
  410.         }
  411.         if (DataObject::doHideUnpublished() && is_array($data)) {
  412.             $publishedList = [];
  413.             foreach ($data as $listElement) {
  414.                 if (Element\Service::isPublished($listElement)) {
  415.                     $publishedList[] = $listElement;
  416.                 }
  417.             }
  418.             return $publishedList;
  419.         }
  420.         return is_array($data) ? $data : [];
  421.     }
  422.     /**
  423.      * { @inheritdoc }
  424.      */
  425.     public function preSetData(/** mixed */ $container/**  mixed */ $data/** array */ $params = []) // : mixed
  426.     {
  427.         if ($data === null) {
  428.             $data = [];
  429.         }
  430.         $this->markLazyloadedFieldAsLoaded($container);
  431.         return $data;
  432.     }
  433.     /**
  434.      * @param int|null $maxItems
  435.      *
  436.      * @return $this
  437.      */
  438.     public function setMaxItems($maxItems)
  439.     {
  440.         $this->maxItems $this->getAsIntegerCast($maxItems);
  441.         return $this;
  442.     }
  443.     /**
  444.      * @return int|null
  445.      */
  446.     public function getMaxItems()
  447.     {
  448.         return $this->maxItems;
  449.     }
  450.     /**
  451.      * {@inheritdoc}
  452.      */
  453.     public function isDiffChangeAllowed($object$params = [])
  454.     {
  455.         return true;
  456.     }
  457.     /** Generates a pretty version preview (similar to getVersionPreview) can be either html or
  458.      * a image URL. See the https://github.com/pimcore/object-merger bundle documentation for details
  459.      *
  460.      * @param Element\ElementInterface[]|null $data
  461.      * @param DataObject\Concrete|null $object
  462.      * @param mixed $params
  463.      *
  464.      * @return array
  465.      */
  466.     public function getDiffVersionPreview($data$object null$params = [])
  467.     {
  468.         $value = [];
  469.         $value['type'] = 'html';
  470.         $value['html'] = '';
  471.         if ($data) {
  472.             $html $this->getVersionPreview($data$object$params);
  473.             $value['html'] = $html;
  474.         }
  475.         return $value;
  476.     }
  477.     /**
  478.      * { @inheritdoc }
  479.      */
  480.     public function rewriteIds(/** mixed */ $container/** array */ $idMapping/** array */ $params = []) /** :mixed */
  481.     {
  482.         $data $this->getDataFromObjectParam($container$params);
  483.         $data $this->rewriteIdsService($data$idMapping);
  484.         return $data;
  485.     }
  486.     /**
  487.      * @param DataObject\ClassDefinition\Data\ManyToManyObjectRelation $mainDefinition
  488.      */
  489.     public function synchronizeWithMainDefinition(DataObject\ClassDefinition\Data $mainDefinition)
  490.     {
  491.         $this->maxItems $mainDefinition->maxItems;
  492.         $this->relationType $mainDefinition->relationType;
  493.     }
  494.     /**
  495.      * @deprecated will be removed in Pimcore 11
  496.      *
  497.      * @param DataObject\ClassDefinition\Data\ManyToManyObjectRelation $masterDefinition
  498.      */
  499.     public function synchronizeWithMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
  500.     {
  501.         trigger_deprecation(
  502.             'pimcore/pimcore',
  503.             '10.6.0',
  504.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use %s instead.'__METHOD__str_replace('Master''Main'__METHOD__))
  505.         );
  506.         $this->synchronizeWithMainDefinition($masterDefinition);
  507.     }
  508.     /**
  509.      * {@inheritdoc}
  510.      */
  511.     public function enrichLayoutDefinition(/* ?Concrete */ $object/* array */ $context = []) // : static
  512.     {
  513.         if (!$this->visibleFields) {
  514.             return $this;
  515.         }
  516.         $classIds $this->getClasses();
  517.         if (empty($classIds[0]['classes'])) {
  518.             return $this;
  519.         }
  520.         $classId $classIds[0]['classes'];
  521.         if (is_numeric($classId)) {
  522.             $class DataObject\ClassDefinition::getById($classId);
  523.         } else {
  524.             $class DataObject\ClassDefinition::getByName($classId);
  525.         }
  526.         if (!$class) {
  527.             return $this;
  528.         }
  529.         if (!isset($context['purpose'])) {
  530.             $context['purpose'] = 'layout';
  531.         }
  532.         $this->visibleFieldDefinitions = [];
  533.         $translator \Pimcore::getContainer()->get('translator');
  534.         $visibleFields explode(','$this->visibleFields);
  535.         foreach ($visibleFields as $field) {
  536.             $fd $class->getFieldDefinition($field$context);
  537.             if (!$fd) {
  538.                 $fieldFound false;
  539.                 /** @var Localizedfields|null $localizedfields */
  540.                 $localizedfields $class->getFieldDefinitions($context)['localizedfields'] ?? null;
  541.                 if ($localizedfields) {
  542.                     if ($fd $localizedfields->getFieldDefinition($field)) {
  543.                         $this->visibleFieldDefinitions[$field]['name'] = $fd->getName();
  544.                         $this->visibleFieldDefinitions[$field]['title'] = $fd->getTitle();
  545.                         $this->visibleFieldDefinitions[$field]['fieldtype'] = $fd->getFieldType();
  546.                         if ($fd instanceof DataObject\ClassDefinition\Data\Select || $fd instanceof DataObject\ClassDefinition\Data\Multiselect) {
  547.                             $this->visibleFieldDefinitions[$field]['options'] = $fd->getOptions();
  548.                         }
  549.                         $fieldFound true;
  550.                     }
  551.                 }
  552.                 if (!$fieldFound) {
  553.                     $this->visibleFieldDefinitions[$field]['name'] = $field;
  554.                     $this->visibleFieldDefinitions[$field]['title'] = $translator->trans($field, [], 'admin');
  555.                     $this->visibleFieldDefinitions[$field]['fieldtype'] = 'input';
  556.                 }
  557.             } else {
  558.                 $this->visibleFieldDefinitions[$field]['name'] = $fd->getName();
  559.                 $this->visibleFieldDefinitions[$field]['title'] = $fd->getTitle();
  560.                 $this->visibleFieldDefinitions[$field]['fieldtype'] = $fd->getFieldType();
  561.                 $this->visibleFieldDefinitions[$field]['noteditable'] = true;
  562.                 if (
  563.                     $fd instanceof DataObject\ClassDefinition\Data\Select
  564.                     || $fd instanceof DataObject\ClassDefinition\Data\Multiselect
  565.                     || $fd instanceof DataObject\ClassDefinition\Data\BooleanSelect
  566.                 ) {
  567.                     if (
  568.                         $fd instanceof DataObject\ClassDefinition\Data\Select
  569.                         || $fd instanceof DataObject\ClassDefinition\Data\Multiselect
  570.                     ) {
  571.                         $this->visibleFieldDefinitions[$field]['optionsProviderClass'] = $fd->getOptionsProviderClass();
  572.                     }
  573.                     $this->visibleFieldDefinitions[$field]['options'] = $fd->getOptions();
  574.                 }
  575.             }
  576.         }
  577.         return $this;
  578.     }
  579.     /**
  580.      * {@inheritdoc}
  581.      */
  582.     protected function getPhpdocType()
  583.     {
  584.         return implode(' | '$this->getPhpDocClassString(true));
  585.     }
  586.     /**
  587.      * {@inheritdoc}
  588.      */
  589.     public function normalize($value$params = [])
  590.     {
  591.         if (is_array($value)) {
  592.             $result = [];
  593.             foreach ($value as $element) {
  594.                 $type Element\Service::getElementType($element);
  595.                 $id $element->getId();
  596.                 $result[] = [
  597.                     'type' => $type,
  598.                     'id' => $id,
  599.                 ];
  600.             }
  601.             return $result;
  602.         }
  603.         return null;
  604.     }
  605.     /**
  606.      * {@inheritdoc}
  607.      */
  608.     public function denormalize($value$params = [])
  609.     {
  610.         if (is_array($value)) {
  611.             $result = [];
  612.             foreach ($value as $elementData) {
  613.                 $type $elementData['type'];
  614.                 $id $elementData['id'];
  615.                 $element Element\Service::getElementById($type$id);
  616.                 if ($element) {
  617.                     $result[] = $element;
  618.                 }
  619.             }
  620.             return $result;
  621.         }
  622.         return null;
  623.     }
  624.     /**
  625.      * Returns a ID which must be unique across the grid rows
  626.      *
  627.      * @internal
  628.      *
  629.      * @param array $item
  630.      *
  631.      * @return string
  632.      */
  633.     protected function buildUniqueKeyForDiffEditor($item)
  634.     {
  635.         return $item['id'];
  636.     }
  637.     /**
  638.      * @internal
  639.      *
  640.      * @param mixed $originalData
  641.      * @param mixed $data
  642.      * @param Concrete $object
  643.      * @param array $params
  644.      *
  645.      * @return array
  646.      */
  647.     protected function processDiffDataForEditMode($originalData$data$object null$params = [])
  648.     {
  649.         if ($data) {
  650.             $data $data[0];
  651.             $items $data['data'];
  652.             $newItems = [];
  653.             if ($items) {
  654.                 foreach ($items as $in) {
  655.                     $item = [];
  656.                     $item['id'] = $in['id'];
  657.                     $item['path'] = $in['fullpath'];
  658.                     $item['type'] = $in['type'];
  659.                     $unique $this->buildUniqueKeyForDiffEditor($item);
  660.                     $itemId json_encode($item);
  661.                     $raw $itemId;
  662.                     $newItems[] = [
  663.                         'itemId' => $itemId,
  664.                         'title' => $item['path'],
  665.                         'raw' => $raw,
  666.                         'gridrow' => $item,
  667.                         'unique' => $unique,
  668.                     ];
  669.                 }
  670.                 $data['data'] = $newItems;
  671.             }
  672.             $data['value'] = [
  673.                 'type' => 'grid',
  674.                 'columnConfig' => [
  675.                     'id' => [
  676.                         'width' => 60,
  677.                     ],
  678.                     'path' => [
  679.                         'flex' => 2,
  680.                     ],
  681.                 ],
  682.                 'html' => $this->getVersionPreview($originalData$object$params),
  683.             ];
  684.             $newData = [];
  685.             $newData[] = $data;
  686.             return $newData;
  687.         }
  688.         return $data;
  689.     }
  690.     /**
  691.      * {@inheritdoc}
  692.      */
  693.     public function getDiffDataForEditMode($data$object null$params = [])
  694.     {
  695.         $originalData $data;
  696.         $data parent::getDiffDataForEditMode($data$object$params);
  697.         $data $this->processDiffDataForEditMode($originalData$data$object$params);
  698.         return $data;
  699.     }
  700.     /** See parent class.
  701.      *
  702.      * @param array $data
  703.      * @param DataObject\Concrete|null $object
  704.      * @param mixed $params
  705.      *
  706.      * @return array|null
  707.      */
  708.     public function getDiffDataFromEditmode($data$object null$params = [])
  709.     {
  710.         if ($data) {
  711.             $tabledata $data[0]['data'];
  712.             $result = [];
  713.             if ($tabledata) {
  714.                 foreach ($tabledata as $in) {
  715.                     $out json_decode($in['raw'], true);
  716.                     $result[] = $out;
  717.                 }
  718.             }
  719.             return $this->getDataFromEditmode($result$object$params);
  720.         }
  721.         return null;
  722.     }
  723.     /**
  724.      * @param array|string|null $visibleFields
  725.      *
  726.      * @return $this
  727.      */
  728.     public function setVisibleFields($visibleFields)
  729.     {
  730.         if (is_array($visibleFields) && count($visibleFields)) {
  731.             $visibleFields implode(','$visibleFields);
  732.         }
  733.         $this->visibleFields $visibleFields;
  734.         return $this;
  735.     }
  736.     /**
  737.      * @return string|null
  738.      */
  739.     public function getVisibleFields()
  740.     {
  741.         return $this->visibleFields;
  742.     }
  743.     /**
  744.      * @return bool
  745.      */
  746.     public function isAllowToCreateNewObject(): bool
  747.     {
  748.         return $this->allowToCreateNewObject;
  749.     }
  750.     /**
  751.      * @param bool $allowToCreateNewObject
  752.      */
  753.     public function setAllowToCreateNewObject($allowToCreateNewObject)
  754.     {
  755.         $this->allowToCreateNewObject = (bool)$allowToCreateNewObject;
  756.     }
  757.     /**
  758.      * {@inheritdoc}
  759.      */
  760.     public function isOptimizedAdminLoading(): bool
  761.     {
  762.         return (bool) $this->optimizedAdminLoading;
  763.     }
  764.     /**
  765.      * @param bool $optimizedAdminLoading
  766.      */
  767.     public function setOptimizedAdminLoading($optimizedAdminLoading)
  768.     {
  769.         $this->optimizedAdminLoading $optimizedAdminLoading;
  770.     }
  771.     /**
  772.      * @return bool
  773.      */
  774.     public function isEnableTextSelection(): bool
  775.     {
  776.         return $this->enableTextSelection;
  777.     }
  778.     /**
  779.      * @param bool $enableTextSelection
  780.      */
  781.     public function setEnableTextSelection(bool $enableTextSelection): void
  782.     {
  783.         $this->enableTextSelection $enableTextSelection;
  784.     }
  785.     /**
  786.      * {@inheritdoc}
  787.      */
  788.     public function isFilterable(): bool
  789.     {
  790.         return true;
  791.     }
  792.     /**
  793.      * {@inheritdoc}
  794.      */
  795.     public function addListingFilter(DataObject\Listing $listing$data$operator '=')
  796.     {
  797.         if ($data instanceof DataObject\Concrete) {
  798.             $data $data->getId();
  799.         }
  800.         if ($operator === '=') {
  801.             $listing->addConditionParam('`'.$this->getName().'` LIKE ?''%,'.$data.',%');
  802.             return $listing;
  803.         }
  804.         return parent::addListingFilter($listing$data$operator);
  805.     }
  806.     /**
  807.      * Filter by relation feature
  808.      *
  809.      * @param array|string|null $value
  810.      * @param string            $operator
  811.      * @param array             $params
  812.      *
  813.      * @return string
  814.      */
  815.     public function getFilterConditionExt($value$operator$params = [])
  816.     {
  817.         $name $params['name'] ?: $this->name;
  818.         return $this->getRelationFilterCondition($value$operator$name);
  819.     }
  820. }