Completed
Pull Request — master (#992)
by David
05:34
created

transformObjectToDocument()   C

Complexity

Conditions 14
Paths 26

Size

Total Lines 56
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 14.0072

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 56
ccs 29
cts 30
cp 0.9667
rs 6.6598
c 2
b 0
f 0
cc 14
eloc 31
nc 26
nop 3
crap 14.0072

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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