Completed
Pull Request — master (#1571)
by
unknown
10:12 queued 08:35
created

AbstractElasticaToModelTransformer   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 9.8%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 4
dl 0
loc 150
ccs 5
cts 51
cp 0.098
rs 10
c 0
b 0
f 0

6 Methods

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