Completed
Branch master (411345)
by Rémi
11:20
created

ObjectWrapper::setEntityAttributes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Analogue\ORM\System\Wrappers;
4
5
use Zend\Hydrator\HydratorInterface;
6
use Analogue\ORM\Exceptions\MappingException;
7
8
/**
9
 * Mixed wrapper using HydratorGenerator
10
 */
11
class ObjectWrapper extends Wrapper
12
{
13
    /** 
14
     * Internal Representation of analogue's entity attributes
15
     * 
16
     * @var  array
17
     */
18
    protected $attributes = [];
19
20
    /** 
21
     * Object properties that are not a part of the entity attributes,
22
     * but which are needed to correctly hydrate the Object
23
     * 
24
     * @var array
25
     */
26
    protected $unmanagedProperties = [];
27
28
    /**
29
     * The hydrator for the wrapped object
30
     * 
31
     * @var  HydratorInterface
32
     */
33
    protected $hydrator;
34
35
    /**
36
     * Object Wrapper constructor
37
     * 
38
     * @param mixed $object
0 ignored issues
show
Bug introduced by
There is no parameter named $object. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
39
     * @param Analogue\ORM\EntityMap $entityMap
40
     * 
41
     * @return  void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
42
     */
43
    public function __construct($entity, $entityMap, HydratorInterface $hydrator)
44
    {
45
        $this->hydrator = $hydrator;
46
        parent::__construct($entity, $entityMap);
47
        $this->attributes = $this->dehydrate($entity);
48
    }
49
50
    /**
51
     * Returns the wrapped entity
52
     *
53
     * @return mixed
54
     */
55
    public function getObject()
56
    {   
57
        $this->hydrate();
58
        return $this->entity;
59
    }
60
61
    /**  
62
     * Extract entity attributes / properties to an array of attributes
63
     * 
64
     * @param  mixed $entity 
65
     * @return array
66
     */
67
    protected function dehydrate($entity) : array
68
    {
69
        $properties = $this->hydrator->extract($entity);
70
71
        $this->unmanagedProperties = array_except($properties, $this->getManagedProperties());
72
73
        return $this->attributesFromProperties($properties);
74
    }
75
76
    /**  
77
     * Hydrate object's properties/attribute from the internal array representation
78
     * 
79
     * @return mixed
80
     */
81
    public function hydrate()
82
    {
83
        $properties = $this->propertiesFromAttributes($this->attributes) + $this->unmanagedProperties;
84
        $this->hydrator->hydrate($properties, $this->entity);
85
    }
86
87
    /**  
88
     * Return properties that will be extracted from the entity
89
     * 
90
     * @return array
91
     */
92
    protected function getManagedProperties() : array
93
    {
94
        $properties = $this->entityMap->getProperties();
95
96
        $attributesName = $this->entityMap->getAttributesArrayName();
97
        
98
        return $attributesName == null ? $properties : array_merge($properties, [$attributesName]);
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $attributesName of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
99
    }
100
101
    /** 
102
     * Convert object's properties to analogue's internal attributes representation
103
     * 
104
     * @param  array  $properties 
105
     * @return array
106
     */
107
    protected function attributesFromProperties(array $properties) : array
108
    {
109
        // First, we'll only keep the entities that are part of the Entity's
110
        // attributes
111
        $managedProperties = $this->getManagedProperties();
112
113
        $properties = array_only($properties, $managedProperties);
114
115
        // If the entity does not uses the attributes array to store
116
        // part of its attributes, we'll directly return the properties
117
        if(! $this->entityMap->usesAttributesArray()) {
118
            return $properties;
119
        }
120
121
        $arrayName = $this->entityMap->getAttributesArrayName();
122
        
123
        if(! array_key_exists($arrayName, $properties)) {
124
            throw new MappingException("Property $arrayName not set on object of type ".$this->getEntityClass());
125
        }
126
127
        if(! is_array($properties[$arrayName])) {
128
            throw new MappingException("Property $arrayName should be an array.");
129
        }
130
131
        $attributes = $properties[$arrayName];
132
133
        unset($properties[$arrayName]);
134
135
        return $properties + $attributes;
136
    }
137
138
    /**  
139
     * Convert internal representation of attributes to an array of properties
140
     * that can hydrate the actual object.
141
     * 
142
     * @param  array  $attributes 
143
     * @return array
144
     */
145
    protected function propertiesFromAttributes(array $attributes) : array
0 ignored issues
show
Unused Code introduced by
The parameter $attributes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
146
    {
147
        $attributes = $this->attributes;
148
149
        // Get all managed properties 
150
        $propertyNames = $this->entityMap->getProperties();
151
152
        $propertyAttributes = array_only($attributes, $propertyNames);
153
        $attributesArray = array_except($attributes, $propertyNames);
154
155
        $attributesArrayName = $this->entityMap->getAttributesArrayName();
156
157
        if($attributesArrayName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $attributesArrayName of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
158
            $propertyAttributes[$attributesArrayName] = $attributesArray;
159
        }
160
161
        return $propertyAttributes;
162
    }
163
    
164
    /**
165
     * Method used by the mapper to set the object
166
     * attribute raw values (hydration)
167
     *
168
     * @param array $attributes
169
     *
170
     * @return void
171
     */
172
    public function setEntityAttributes(array $attributes)
173
    {
174
        $this->attributes = $attributes;
175
    }
176
177
    /**
178
     * Method used by the mapper to get the
179
     * raw object's values.
180
     *
181
     * @return array
182
     */
183
    public function getEntityAttributes() : array
184
    {
185
        return $this->attributes;
186
    }
187
188
    /**
189
     * Method used by the mapper to set raw
190
     * key-value pair
191
     *
192
     * @param string $key
193
     * @param string $value
194
     *
195
     * @return void
196
     */
197
    public function setEntityAttribute($key, $value)
198
    {
199
        $this->attributes[$key] = $value;
200
    }
201
202
    /**
203
     * Method used by the mapper to get single
204
     * key-value pair
205
     *
206
     * @param  string $key
207
     * @return mixed|null
208
     */
209
    public function getEntityAttribute($key)
210
    {
211
        if ($this->hasAttribute($key)) {
212
            return $this->attributes[$key];
213
        } else {
214
            return null;
215
        }
216
    }
217
218
    /**
219
     * Test if a given attribute exists
220
     *
221
     * @param  string $key
222
     * @return boolean
223
     */
224
    public function hasAttribute($key) : bool
225
    {
226
        return array_key_exists($key, $this->attributes) ? true : false;
227
    }
228
}
229