vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/ManyToManyRelation.php line 376

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