Completed
Push — master ( fbc1fa...9bba21 )
by
unknown
14s
created

ModelToElasticaAutoTransformer   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 188
Duplicated Lines 6.38 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 32
c 0
b 0
f 0
lcom 1
cbo 4
dl 12
loc 188
ccs 0
cts 93
cp 0
rs 9.6

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setPropertyAccessor() 0 4 1
A transform() 0 7 1
B transformNested() 0 18 6
B normalizeValue() 0 19 8
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\PropertyAccess\PropertyAccessorInterface;
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
class ModelToElasticaAutoTransformer implements ModelToElasticaTransformerInterface
25
{
26
    /**
27
     * @var EventDispatcherInterface
28
     */
29
    protected $dispatcher;
30
31
    /**
32
     * Optional parameters.
33
     *
34
     * @var array
35
     */
36
    protected $options = [
37
        'identifier' => 'id',
38
    ];
39
40
    /**
41
     * PropertyAccessor instance.
42
     *
43
     * @var PropertyAccessorInterface
44
     */
45
    protected $propertyAccessor;
46
47
    /**
48
     * Instanciates a new Mapper.
49
     *
50
     * @param array                    $options
51
     * @param EventDispatcherInterface $dispatcher
52
     */
53
    public function __construct(array $options = [], EventDispatcherInterface $dispatcher = null)
54
    {
55
        $this->options = array_merge($this->options, $options);
56
        $this->dispatcher = $dispatcher;
57
    }
58
59
    /**
60
     * Set the PropertyAccessor.
61
     *
62
     * @param PropertyAccessorInterface $propertyAccessor
63
     */
64
    public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor)
65
    {
66
        $this->propertyAccessor = $propertyAccessor;
67
    }
68
69
    /**
70
     * Transforms an object into an elastica object having the required keys.
71
     *
72
     * @param object $object the object to convert
73
     * @param array  $fields the keys we want to have in the returned array
74
     *
75
     * @return Document
76
     **/
77
    public function transform($object, array $fields)
78
    {
79
        $identifier = $this->propertyAccessor->getValue($object, $this->options['identifier']);
80
        $document = $this->transformObjectToDocument($object, $fields, $identifier);
81
82
        return $document;
83
    }
84
85
    /**
86
     * transform a nested document or an object property into an array of ElasticaDocument.
87
     *
88
     * @param array|\Traversable|\ArrayAccess $objects the object to convert
89
     * @param array                           $fields  the keys we want to have in the returned array
90
     *
91
     * @return array
92
     */
93
    protected function transformNested($objects, array $fields)
94
    {
95
        if (is_array($objects) || $objects instanceof \Traversable || $objects instanceof \ArrayAccess) {
96
            $documents = [];
97
            foreach ($objects as $object) {
98
                $document = $this->transformObjectToDocument($object, $fields);
99
                $documents[] = $document->getData();
100
            }
101
102
            return $documents;
103
        } elseif (null !== $objects) {
104
            $document = $this->transformObjectToDocument($objects, $fields);
105
106
            return $document->getData();
107
        }
108
109
        return [];
110
    }
111
112
    /**
113
     * Attempts to convert any type to a string or an array of strings.
114
     *
115
     * @param mixed $value
116
     *
117
     * @return string|array
118
     */
119
    protected function normalizeValue($value)
120
    {
121
        $normalizeValue = function (&$v) {
122
            if ($v instanceof \DateTimeInterface) {
123
                $v = $v->format('c');
124
            } elseif (!is_scalar($v) && !is_null($v)) {
125
                $v = (string) $v;
126
            }
127
        };
128
129
        if (is_array($value) || $value instanceof \Traversable || $value instanceof \ArrayAccess) {
130
            $value = is_array($value) ? $value : iterator_to_array($value, false);
131
            array_walk_recursive($value, $normalizeValue);
132
        } else {
133
            $normalizeValue($value);
134
        }
135
136
        return $value;
137
    }
138
139
    /**
140
     * Transforms the given object to an elastica document.
141
     *
142
     * @param object $object     the object to convert
143
     * @param array  $fields     the keys we want to have in the returned array
144
     * @param string $identifier the identifier for the new document
145
     *
146
     * @return Document
147
     */
148
    protected function transformObjectToDocument($object, array $fields, $identifier = '')
149
    {
150
        $document = new Document($identifier);
151
152 View Code Duplication
        if ($this->dispatcher) {
153
            $event = new TransformEvent($document, $fields, $object);
154
            $this->dispatcher->dispatch(TransformEvent::PRE_TRANSFORM, $event);
155
156
            $document = $event->getDocument();
157
        }
158
159
        foreach ($fields as $key => $mapping) {
160
            if ('_parent' == $key) {
161
                $property = (null !== $mapping['property']) ? $mapping['property'] : $mapping['type'];
162
                $value = $this->propertyAccessor->getValue($object, $property);
163
                $document->setParent($this->propertyAccessor->getValue($value, $mapping['identifier']));
164
165
                continue;
166
            }
167
168
            $path = isset($mapping['property_path']) ?
169
                $mapping['property_path'] :
170
                $key;
171
            if (false === $path) {
172
                continue;
173
            }
174
            $value = $this->propertyAccessor->getValue($object, $path);
175
176
            if (isset($mapping['type']) && in_array(
177
                    $mapping['type'], ['nested', 'object']
178
                ) && isset($mapping['properties']) && !empty($mapping['properties'])
179
            ) {
180
                /* $value is a nested document or object. Transform $value into
181
                 * an array of documents, respective the mapped properties.
182
                 */
183
                $document->set($key, $this->transformNested($value, $mapping['properties']));
184
185
                continue;
186
            }
187
188
            if (isset($mapping['type']) && 'attachment' == $mapping['type']) {
189
                // $value is an attachment. Add it to the document.
190
                if ($value instanceof \SplFileInfo) {
191
                    $document->addFile($key, $value->getPathName());
192
                } else {
193
                    $document->addFileContent($key, $value);
194
                }
195
196
                continue;
197
            }
198
199
            $document->set($key, $this->normalizeValue($value));
200
        }
201
202 View Code Duplication
        if ($this->dispatcher) {
203
            $event = new TransformEvent($document, $fields, $object);
204
            $this->dispatcher->dispatch(TransformEvent::POST_TRANSFORM, $event);
205
206
            $document = $event->getDocument();
207
        }
208
209
        return $document;
210
    }
211
}
212