vendor/friendsofsymfony/elastica-bundle/src/Transformer/ModelToElasticaAutoTransformer.php line 61

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the FOSElasticaBundle package.
  4.  *
  5.  * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace FOS\ElasticaBundle\Transformer;
  11. use Elastica\Document;
  12. use FOS\ElasticaBundle\Event\TransformEvent;
  13. use Symfony\Component\EventDispatcher\EventDispatcherInterface as LegacyEventDispatcherInterface;
  14. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  15. use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
  16. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  17. /**
  18.  * Maps Elastica documents with Doctrine objects
  19.  * This mapper assumes an exact match between
  20.  * elastica documents ids and doctrine object ids.
  21.  */
  22. class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterface
  23. {
  24.     /**
  25.      * @var EventDispatcherInterface|LegacyEventDispatcherInterface
  26.      */
  27.     protected $dispatcher;
  28.     /**
  29.      * Optional parameters.
  30.      *
  31.      * @var array
  32.      */
  33.     protected $options = [
  34.         'identifier' => 'id',
  35.         'index' => '',
  36.     ];
  37.     /**
  38.      * PropertyAccessor instance.
  39.      *
  40.      * @var PropertyAccessorInterface
  41.      */
  42.     protected $propertyAccessor;
  43.     /**
  44.      * Instanciates a new Mapper.
  45.      *
  46.      * @param array                                                   $options
  47.      * @param EventDispatcherInterface|LegacyEventDispatcherInterface $dispatcher
  48.      */
  49.     public function __construct(array $options = [], /* EventDispatcherInterface */ $dispatcher null)
  50.     {
  51.         $this->options array_merge($this->options$options);
  52.         $this->dispatcher $dispatcher;
  53.         if (class_exists(LegacyEventDispatcherProxy::class)) {
  54.             $this->dispatcher LegacyEventDispatcherProxy::decorate($dispatcher);
  55.         }
  56.     }
  57.     /**
  58.      * Set the PropertyAccessor.
  59.      *
  60.      * @param PropertyAccessorInterface $propertyAccessor
  61.      */
  62.     public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor)
  63.     {
  64.         $this->propertyAccessor $propertyAccessor;
  65.     }
  66.     /**
  67.      * Transforms an object into an elastica object having the required keys.
  68.      *
  69.      * @param object $object the object to convert
  70.      * @param array  $fields the keys we want to have in the returned array
  71.      *
  72.      * @return Document
  73.      **/
  74.     public function transform($object, array $fields)
  75.     {
  76.         $identifier $this->propertyAccessor->getValue($object$this->options['identifier']);
  77.         if ($identifier && !is_scalar($identifier)) {
  78.             $identifier = (string) $identifier;
  79.         }
  80.         return $this->transformObjectToDocument($object$fields$identifier);
  81.     }
  82.     /**
  83.      * transform a nested document or an object property into an array of ElasticaDocument.
  84.      *
  85.      * @param array|\Traversable|\ArrayAccess $objects the object to convert
  86.      * @param array                           $fields  the keys we want to have in the returned array
  87.      *
  88.      * @return array
  89.      */
  90.     protected function transformNested($objects, array $fields)
  91.     {
  92.         if (is_array($objects) || $objects instanceof \Traversable || $objects instanceof \ArrayAccess) {
  93.             $documents = [];
  94.             foreach ($objects as $object) {
  95.                 $document $this->transformObjectToDocument($object$fields);
  96.                 $documents[] = $document->getData();
  97.             }
  98.             return $documents;
  99.         } elseif (null !== $objects) {
  100.             $document $this->transformObjectToDocument($objects$fields);
  101.             return $document->getData();
  102.         }
  103.         return [];
  104.     }
  105.     /**
  106.      * Attempts to convert any type to a string or an array of strings.
  107.      *
  108.      * @param mixed $value
  109.      *
  110.      * @return string|array
  111.      */
  112.     protected function normalizeValue($value)
  113.     {
  114.         $normalizeValue = function (&$v) {
  115.             if ($v instanceof \DateTimeInterface) {
  116.                 $v $v->format('c');
  117.             } elseif (!is_scalar($v) && !is_null($v)) {
  118.                 $v = (string) $v;
  119.             }
  120.         };
  121.         if (is_array($value) || $value instanceof \Traversable || $value instanceof \ArrayAccess) {
  122.             $value is_array($value) ? $value iterator_to_array($valuefalse);
  123.             array_walk_recursive($value$normalizeValue);
  124.         } else {
  125.             $normalizeValue($value);
  126.         }
  127.         return $value;
  128.     }
  129.     /**
  130.      * Transforms the given object to an elastica document.
  131.      *
  132.      * @param object $object     the object to convert
  133.      * @param array  $fields     the keys we want to have in the returned array
  134.      * @param string $identifier the identifier for the new document
  135.      *
  136.      * @return Document
  137.      */
  138.     protected function transformObjectToDocument($object, array $fields$identifier '')
  139.     {
  140.         $document = new Document($identifier, [], ''$this->options['index']);
  141.         if ($this->dispatcher) {
  142.             $event = new TransformEvent($document$fields$object);
  143.             $this->dispatch($eventTransformEvent::PRE_TRANSFORM);
  144.             $document $event->getDocument();
  145.         }
  146.         foreach ($fields as $key => $mapping) {
  147.             if ('_parent' == $key) {
  148.                 $property = (null !== $mapping['property']) ? $mapping['property'] : $mapping['type'];
  149.                 $value $this->propertyAccessor->getValue($object$property);
  150.                 $document->setParent($this->propertyAccessor->getValue($value$mapping['identifier']));
  151.                 continue;
  152.             }
  153.             $path = isset($mapping['property_path']) ?
  154.                 $mapping['property_path'] :
  155.                 $key;
  156.             if (false === $path) {
  157.                 continue;
  158.             }
  159.             $value $this->propertyAccessor->getValue($object$path);
  160.             if (isset($mapping['type']) && in_array(
  161.                     $mapping['type'], ['nested''object']
  162.                 ) && isset($mapping['properties']) && !empty($mapping['properties'])
  163.             ) {
  164.                 /* $value is a nested document or object. Transform $value into
  165.                  * an array of documents, respective the mapped properties.
  166.                  */
  167.                 $document->set($key$this->transformNested($value$mapping['properties']));
  168.                 continue;
  169.             }
  170.             if (isset($mapping['type']) && 'attachment' == $mapping['type']) {
  171.                 // $value is an attachment. Add it to the document.
  172.                 if ($value instanceof \SplFileInfo) {
  173.                     $document->addFile($key$value->getPathName());
  174.                 } else {
  175.                     $document->addFileContent($key$value);
  176.                 }
  177.                 continue;
  178.             }
  179.             $document->set($key$this->normalizeValue($value));
  180.         }
  181.         if ($this->dispatcher) {
  182.             $event = new TransformEvent($document$fields$object);
  183.             $this->dispatch($eventTransformEvent::POST_TRANSFORM);
  184.             $document $event->getDocument();
  185.         }
  186.         return $document;
  187.     }
  188.     private function dispatch($event$eventName): void
  189.     {
  190.         if ($this->dispatcher instanceof EventDispatcherInterface) {
  191.             // Symfony >= 4.3
  192.             $this->dispatcher->dispatch($event$eventName);
  193.         } else {
  194.             // Symfony 3.4
  195.             $this->dispatcher->dispatch($eventName$event);
  196.         }
  197.     }
  198. }