Completed
Pull Request — master (#1134)
by Istvan
14:27
created

AbstractElasticaToModelTransformer::transform()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 42
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 7.0018

Importance

Changes 4
Bugs 2 Features 1
Metric Value
c 4
b 2
f 1
dl 0
loc 42
ccs 29
cts 30
cp 0.9667
rs 6.7272
cc 7
eloc 28
nc 8
nop 1
crap 7.0018
1
<?php
2
3
namespace FOS\ElasticaBundle\Doctrine;
4
5
use Doctrine\Common\Persistence\ManagerRegistry;
6
use FOS\ElasticaBundle\HybridResult;
7
use FOS\ElasticaBundle\Transformer\AbstractElasticaToModelTransformer as BaseTransformer;
8
use FOS\ElasticaBundle\Transformer\HighlightableModelInterface;
9
10
/**
11
 * Maps Elastica documents with Doctrine objects
12
 * This mapper assumes an exact match between
13
 * elastica documents ids and doctrine object ids.
14
 */
15
abstract class AbstractElasticaToModelTransformer extends BaseTransformer
16
{
17
    /**
18
     * Manager registry.
19
     *
20
     * @var ManagerRegistry
21
     */
22
    protected $registry = null;
23
24
    /**
25
     * Class of the model to map to the elastica documents.
26
     *
27
     * @var string
28
     */
29
    protected $objectClass = null;
30
31
    /**
32
     * Optional parameters.
33
     *
34
     * @var array
35
     */
36
    protected $options = array(
37
        'hints'        => array(),
38
        'hydrate'        => true,
39
        'identifier'     => 'id',
40
        'ignore_missing' => false,
41
        'query_builder_method' => 'createQueryBuilder',
42
    );
43
44
    /**
45
     * Instantiates a new Mapper.
46
     *
47
     * @param ManagerRegistry $registry
48
     * @param string          $objectClass
49
     * @param array           $options
50
     */
51 13
    public function __construct(ManagerRegistry $registry, $objectClass, array $options = array())
52
    {
53 13
        $this->registry    = $registry;
54 13
        $this->objectClass = $objectClass;
55 13
        $this->options     = array_merge($this->options, $options);
56 13
    }
57
58
    /**
59
     * Returns the object class that is used for conversion.
60
     *
61
     * @return string
62
     */
63 1
    public function getObjectClass()
64
    {
65 1
        return $this->objectClass;
66
    }
67
68
    /**
69
     * Transforms an array of elastica objects into an array of
70
     * model objects fetched from the doctrine repository.
71
     *
72
     * @param array $elasticaObjects of elastica objects
73
     *
74
     * @throws \RuntimeException
75
     *
76
     * @return array
77
     **/
78 7
    public function transform(array $elasticaObjects)
79
    {
80 7
        $ids = $highlights = array();
81 7
        foreach ($elasticaObjects as $elasticaObject) {
82 7
            $ids[] = $elasticaObject->getId();
83 7
            $highlights[$elasticaObject->getId()] = $elasticaObject->getHighlights();
84 7
        }
85
86 7
        $objects = $this->findByIdentifiers($ids, $this->options['hydrate']);
87 7
        $objectsCnt = count($objects);
88 7
        $elasticaObjectsCnt = count($elasticaObjects);
89 7
        if (!$this->options['ignore_missing'] && $objectsCnt < $elasticaObjectsCnt) {
90 1
            throw new \RuntimeException(sprintf('Cannot find corresponding Doctrine objects (%d) for all Elastica results (%d). IDs: %s', $objectsCnt, $elasticaObjectsCnt, join(', ', $ids)));
91
        };
92
93 6
        $propertyAccessor = $this->propertyAccessor;
94 6
        $identifier = $this->options['identifier'];
95 6
        foreach ($objects as $object) {
96 5
            if ($object instanceof HighlightableModelInterface) {
97 4
                $id = $propertyAccessor->getValue($object, $identifier);
98 4
                $object->setElasticHighlights($highlights[(string) $id]);
99 4
            }
100 6
        }
101
102
        // sort objects in the order of ids
103 6
        $idPos = array_flip($ids);
104 6
        usort(
105 6
            $objects,
106 5
            function ($a, $b) use ($idPos, $identifier, $propertyAccessor) {
107 5
                if ($this->options['hydrate']) {
108 5
                    return $idPos[(string)$propertyAccessor->getValue(
109 5
                        $a,
110
                        $identifier
111 5
                    )] > $idPos[(string)$propertyAccessor->getValue($b, $identifier)];
112
                } else {
113
                    return $idPos[$a[$identifier]] > $idPos[$b[$identifier]];
114
                }
115
            }
116 6
        );
117
118 6
        return $objects;
119
    }
120
121 2
    public function hybridTransform(array $elasticaObjects)
122
    {
123 2
        $indexedElasticaResults = array();
124 2
        foreach ($elasticaObjects as $elasticaObject) {
125 2
            $indexedElasticaResults[(string) $elasticaObject->getId()] = $elasticaObject;
126 2
        }
127
128 2
        $objects = $this->transform($elasticaObjects);
129
130 2
        $result = array();
131 2
        foreach ($objects as $object) {
132 2
            if ($this->options['hydrate']) {
133 2
                $id = $this->propertyAccessor->getValue($object, $this->options['identifier']);
134 2
            } else {
135
                $id = $object[$this->options['identifier']];
136
            }
137 2
            $result[] = new HybridResult($indexedElasticaResults[(string) $id], $object);
138 2
        }
139
140 2
        return $result;
141
    }
142
143
    /**
144
     * {@inheritDoc}
145
     */
146 1
    public function getIdentifierField()
147
    {
148 1
        return $this->options['identifier'];
149
    }
150
151
    /**
152
     * Fetches objects by theses identifier values.
153
     *
154
     * @param array   $identifierValues ids values
155
     * @param Boolean $hydrate          whether or not to hydrate the objects, false returns arrays
156
     *
157
     * @return array of objects or arrays
158
     */
159
    abstract protected function findByIdentifiers(array $identifierValues, $hydrate);
160
}
161