Completed
Pull Request — master (#1570)
by
unknown
16:14
created

ModelToElasticaAutoTransformer   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 195
Duplicated Lines 10.77 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 92.86%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 4
dl 21
loc 195
ccs 65
cts 70
cp 0.9286
rs 9.6
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A setPropertyAccessor() 0 4 1
A transform() 0 9 3
A transformNested() 0 18 6
B normalizeValue() 0 19 8
A __construct() 9 9 2
C transformObjectToDocument() 12 63 15

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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\Transformer;
13
14
use Elastica\Document;
15
use FOS\ElasticaBundle\Event\TransformEvent;
16
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
18
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
19
20
/**
21
 * Maps Elastica documents with Doctrine objects
22
 * This mapper assumes an exact match between
23
 * elastica documents ids and doctrine object ids.
24
 */
25
class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterface
26
{
27
    /**
28
     * @var EventDispatcherInterface
29
     */
30
    protected $dispatcher;
31
32
    /**
33
     * Optional parameters.
34
     *
35
     * @var array
36
     */
37
    protected $options = [
38
        'identifier' => 'id',
39
        'index' => '',
40
    ];
41
42
    /**
43
     * PropertyAccessor instance.
44
     *
45
     * @var PropertyAccessorInterface
46
     */
47
    protected $propertyAccessor;
48
49
    /**
50
     * Instanciates a new Mapper.
51
     *
52
     * @param array                    $options
53
     * @param EventDispatcherInterface $dispatcher
54
     */
55 45 View Code Duplication
    public function __construct(array $options = [], EventDispatcherInterface $dispatcher = null)
56
    {
57 45
        $this->options = array_merge($this->options, $options);
58 45
        $this->dispatcher = $dispatcher;
59
60 45
        if (class_exists(LegacyEventDispatcherProxy::class)) {
61
            $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
62
        }
63 45
    }
64
65
    /**
66
     * Set the PropertyAccessor.
67
     *
68
     * @param PropertyAccessorInterface $propertyAccessor
69
     */
70 45
    public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor)
71
    {
72 45
        $this->propertyAccessor = $propertyAccessor;
73 45
    }
74
75
    /**
76
     * Transforms an object into an elastica object having the required keys.
77
     *
78
     * @param object $object the object to convert
79
     * @param array  $fields the keys we want to have in the returned array
80
     *
81
     * @return Document
82
     **/
83 30
    public function transform($object, array $fields)
84
    {
85 30
        $identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']);
86 30
        if ($identifier && !is_scalar($identifier)) {
87 1
            $identifier = (string) $identifier;
88
        }
89
90 30
        return $this->transformObjectToDocument($object, $fields, $identifier);
91
    }
92
93
    /**
94
     * transform a nested document or an object property into an array of ElasticaDocument.
95
     *
96
     * @param array|\Traversable|\ArrayAccess $objects the object to convert
97
     * @param array                           $fields  the keys we want to have in the returned array
98
     *
99
     * @return array
100
     */
101 6
    protected function transformNested($objects, array $fields)
102
    {
103 6
        if (is_array($objects) || $objects instanceof \Traversable || $objects instanceof \ArrayAccess) {
104 3
            $documents = [];
105 3
            foreach ($objects as $object) {
106 3
                $document = $this->transformObjectToDocument($object, $fields);
107 3
                $documents[] = $document->getData();
108
            }
109
110 3
            return $documents;
111 3
        } elseif (null !== $objects) {
112 2
            $document = $this->transformObjectToDocument($objects, $fields);
113
114 2
            return $document->getData();
115
        }
116
117 1
        return [];
118
    }
119
120
    /**
121
     * Attempts to convert any type to a string or an array of strings.
122
     *
123
     * @param mixed $value
124
     *
125
     * @return string|array
126
     */
127
    protected function normalizeValue($value)
128
    {
129 18
        $normalizeValue = function (&$v) {
130 18
            if ($v instanceof \DateTimeInterface) {
131 2
                $v = $v->format('c');
132 18
            } elseif (!is_scalar($v) && !is_null($v)) {
133 1
                $v = (string) $v;
134
            }
135 18
        };
136
137 18
        if (is_array($value) || $value instanceof \Traversable || $value instanceof \ArrayAccess) {
138 5
            $value = is_array($value) ? $value : iterator_to_array($value, false);
139 5
            array_walk_recursive($value, $normalizeValue);
140
        } else {
141 14
            $normalizeValue($value);
142
        }
143
144 18
        return $value;
145
    }
146
147
    /**
148
     * Transforms the given object to an elastica document.
149
     *
150
     * @param object $object     the object to convert
151
     * @param array  $fields     the keys we want to have in the returned array
152
     * @param string $identifier the identifier for the new document
153
     *
154
     * @return Document
155
     */
156 30
    protected function transformObjectToDocument($object, array $fields, $identifier = '')
157
    {
158 30
        $document = new Document($identifier, [], '', $this->options['index']);
159
160 30 View Code Duplication
        if ($this->dispatcher) {
161 3
            $event = new TransformEvent($document, $fields, $object);
162 3
            $this->dispatcher->dispatch(TransformEvent::PRE_TRANSFORM, $event);
0 ignored issues
show
Documentation introduced by
$event is of type object<FOS\ElasticaBundle\Event\TransformEvent>, but the function expects a null|object<Symfony\Comp...\EventDispatcher\Event>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
163
164
            $document = $event->getDocument();
165
        }
166
167 27
        foreach ($fields as $key => $mapping) {
168 26
            if ('_parent' == $key) {
169 4
                $property = (null !== $mapping['property']) ? $mapping['property'] : $mapping['type'];
170 4
                $value = $this->propertyAccessor->getValue($object, $property);
171 4
                $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier']));
172
173 4
                continue;
174
            }
175
176 22
            $path = isset($mapping['property_path']) ?
177 1
                $mapping['property_path'] :
178 22
                $key;
179 22
            if (false === $path) {
180 1
                continue;
181
            }
182 22
            $value = $this->propertyAccessor->getValue($object, $path);
183
184 21
            if (isset($mapping['type']) && in_array(
185 21
                    $mapping['type'], ['nested', 'object']
186 21
                ) && isset($mapping['properties']) && !empty($mapping['properties'])
187
            ) {
188
                /* $value is a nested document or object. Transform $value into
189
                 * an array of documents, respective the mapped properties.
190
                 */
191 6
                $document->set($key, $this->transformNested($value, $mapping['properties']));
192
193 6
                continue;
194
            }
195
196 20
            if (isset($mapping['type']) && 'attachment' == $mapping['type']) {
197
                // $value is an attachment. Add it to the document.
198 2
                if ($value instanceof \SplFileInfo) {
199 1
                    $document->addFile($key, $value->getPathName());
200
                } else {
201 1
                    $document->addFileContent($key, $value);
202
                }
203
204 2
                continue;
205
            }
206
207 18
            $document->set($key, $this->normalizeValue($value));
208
        }
209
210 26 View Code Duplication
        if ($this->dispatcher) {
211
            $event = new TransformEvent($document, $fields, $object);
212
            $this->dispatcher->dispatch(TransformEvent::POST_TRANSFORM, $event);
0 ignored issues
show
Documentation introduced by
$event is of type object<FOS\ElasticaBundle\Event\TransformEvent>, but the function expects a null|object<Symfony\Comp...\EventDispatcher\Event>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
213
214
            $document = $event->getDocument();
215
        }
216
217 26
        return $document;
218
    }
219
}
220