Failed Conditions
Pull Request — experimental/sf (#3236)
by Kentaro
144:19 queued 116:23
created

AbstractEntity::setPropertiesFromArray()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 24

Duplication

Lines 8
Ratio 33.33 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
nc 12
nop 3
dl 8
loc 24
ccs 15
cts 15
cp 1
crap 6
rs 8.9137
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Entity;
15
16
use Doctrine\Common\Annotations\Reader;
17
use Doctrine\Common\Collections\Collection;
18
use Doctrine\Common\Inflector\Inflector;
19
use Doctrine\ORM\Mapping\MappedSuperclass;
20
use Doctrine\ORM\Mapping\Id;
21
use Doctrine\ORM\Proxy\Proxy;
22
use Symfony\Component\Serializer\Encoder\XmlEncoder;
23
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
24
use Symfony\Component\Serializer\Serializer;
25
26
/** @MappedSuperclass */
27
abstract class AbstractEntity implements \ArrayAccess
28
{
29
    private $AnnotationReader;
30
31 323
    public function offsetExists($offset)
32
    {
33 323
        $method = Inflector::classify($offset);
34
35 323
        return method_exists($this, $method)
36 323
            || method_exists($this, "get$method")
37 323
            || method_exists($this, "is$method")
38 323
            || method_exists($this, "has$method");
39
    }
40
41
    public function offsetSet($offset, $value)
42
    {
43
    }
44
45 330
    public function offsetGet($offset)
46
    {
47 330
        $method = Inflector::classify($offset);
48
49 330
        if (method_exists($this, $method)) {
50 91
            return $this->$method();
51 330
        } elseif (method_exists($this, "get$method")) {
52 317
            return $this->{"get$method"}();
53 172
        } elseif (method_exists($this, "is$method")) {
54 171
            return $this->{"is$method"}();
55 70
        } elseif (method_exists($this, "has$method")) {
56
            return $this->{"has$method"}();
57
        }
58
    }
59
60
    public function offsetUnset($offset)
61
    {
62
    }
63
64
    /**
65
     * 引数の連想配列を元にプロパティを設定します.
66
     * DBから取り出した連想配列を, プロパティへ設定する際に使用します.
67
     *
68
     * @param array $arrProps プロパティの情報を格納した連想配列
69
     * @param \ReflectionClass $parentClass 親のクラス. 本メソッドの内部的に使用します.
70
     * @param string[] $excludeAttribute 除外したいフィールド名の配列
71
     */
72 238
    public function setPropertiesFromArray(array $arrProps, array $excludeAttribute = [], \ReflectionClass $parentClass = null)
73
    {
74 238
        $objReflect = null;
0 ignored issues
show
Unused Code introduced by
$objReflect is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
75 238
        if (is_object($parentClass)) {
76 238
            $objReflect = $parentClass;
77
        } else {
78 238
            $objReflect = new \ReflectionClass($this);
79
        }
80 238
        $arrProperties = $objReflect->getProperties();
81 238 View Code Duplication
        foreach ($arrProperties as $objProperty) {
82 238
            $objProperty->setAccessible(true);
83 238
            $name = $objProperty->getName();
84 238
            if (in_array($name, $excludeAttribute) || !array_key_exists($name, $arrProps)) {
85 238
                continue;
86
            }
87 238
            $objProperty->setValue($this, $arrProps[$name]);
88
        }
89
90
        // 親クラスがある場合は再帰的にプロパティを取得
91 238
        $parentClass = $objReflect->getParentClass();
92 238
        if (is_object($parentClass)) {
93 238
            self::setPropertiesFromArray($arrProps, $excludeAttribute, $parentClass);
94
        }
95
    }
96
97
    /**
98
     * Convert to associative array.
99
     *
100
     * Symfony Serializer Component is expensive, and hard to implementation.
101
     * Use for encoder only.
102
     *
103
     * @param \ReflectionClass $parentClass parent class. Use internally of this method..
104
     * @param array $excludeAttribute Array of field names to exclusion.
105
     *
106
     * @return array
107
     */
108 471
    public function toArray(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'], \ReflectionClass $parentClass = null)
109
    {
110 471
        $objReflect = null;
0 ignored issues
show
Unused Code introduced by
$objReflect is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
111 471
        if (is_object($parentClass)) {
112 471
            $objReflect = $parentClass;
113
        } else {
114 471
            $objReflect = new \ReflectionClass($this);
115
        }
116 471
        $arrProperties = $objReflect->getProperties();
117 471
        $arrResults = [];
118 471 View Code Duplication
        foreach ($arrProperties as $objProperty) {
119 471
            $objProperty->setAccessible(true);
120 471
            $name = $objProperty->getName();
121 471
            if (in_array($name, $excludeAttribute)) {
122 470
                continue;
123
            }
124 471
            $arrResults[$name] = $objProperty->getValue($this);
125
        }
126
127 471
        $parentClass = $objReflect->getParentClass();
128 471
        if (is_object($parentClass)) {
129 471
            $arrParents = self::toArray($excludeAttribute, $parentClass);
130 471
            if (!is_array($arrParents)) {
131
                $arrParents = [];
132
            }
133 471
            if (!is_array($arrResults)) {
134
                $arrResults = [];
135
            }
136 471
            $arrResults = array_merge($arrParents, $arrResults);
137
        }
138
139 471
        return $arrResults;
140
    }
141
142
    /**
143
     * Convert to associative array, and normalize to association properties.
144
     *
145
     * The type conversion such as:
146
     * - Datetime ::  W3C datetime format string
147
     * - AbstractEntity :: associative array such as [id => value]
148
     * - PersistentCollection :: associative array of [[id => value], [id => value], ...]
149
     *
150
     * @param array $excludeAttribute Array of field names to exclusion.
151
     *
152
     * @return array
153
     */
154 3
    public function toNormalizedArray(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'])
155
    {
156 3
        $arrResult = $this->toArray($excludeAttribute);
157 3
        foreach ($arrResult as &$value) {
158 3
            if ($value instanceof \DateTime) {
159
                // see also https://stackoverflow.com/a/17390817/4956633
160 3
                $value->setTimezone(new \DateTimeZone('UTC'));
161 3
                $value = $value->format('Y-m-d\TH:i:s\Z');
162 3
            } elseif ($value instanceof AbstractEntity) {
163
                // Entity の場合は [id => value] の配列を返す
164
                $value = $this->getEntityIdentifierAsArray($value);
165 3
            } elseif ($value instanceof Collection) {
166
                // Collection の場合は ID を持つオブジェクトの配列を返す
167 3
                $Collections = $value;
168 3
                $value = [];
169 3
                foreach ($Collections as $Child) {
170 3
                    $value[] = $this->getEntityIdentifierAsArray($Child);
171
                }
172
            }
173
        }
174
175 3
        return $arrResult;
176
    }
177
178
    /**
179
     * Convert to JSON.
180
     *
181
     * @param array $excludeAttribute Array of field names to exclusion.
182
     *
183
     * @return string
184
     */
185 1
    public function toJSON(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'])
186
    {
187 1
        return json_encode($this->toNormalizedArray($excludeAttribute));
188
    }
189
190
    /**
191
     * Convert to XML.
192
     *
193
     * @param array $excludeAttribute Array of field names to exclusion.
194
     *
195
     * @return string
196
     */
197 1
    public function toXML(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'])
198
    {
199 1
        $ReflectionClass = new \ReflectionClass($this);
200 1
        $serializer = new Serializer([new PropertyNormalizer()], [new XmlEncoder($ReflectionClass->getShortName())]);
201
202 1
        return $serializer->serialize($this->toNormalizedArray($excludeAttribute), 'xml');
203
    }
204
205
    /**
206
     * コピー元のオブジェクトのフィールド名を指定して、同名のフィールドに値をコピー
207
     *
208
     * @param object $srcObject コピー元のオブジェクト
209
     * @param string[] $excludeAttribute 除外したいフィールド名の配列
210
     *
211
     * @return AbstractEntity
212
     */
213 207
    public function copyProperties($srcObject, array $excludeAttribute = [])
214
    {
215 207
        $this->setPropertiesFromArray($srcObject->toArray($excludeAttribute), $excludeAttribute);
216
217 207
        return $this;
218
    }
219
220
    /**
221
     * Set AnnotationReader.
222
     *
223
     * @param Reader $Reader
224
     *
225
     * @return AbstractEntity
226
     */
227 1017
    public function setAnnotationReader(Reader $Reader)
228
    {
229 1017
        $this->AnnotationReader = $Reader;
230
231 1017
        return $this;
232
    }
233
234
    /**
235
     * Get AnnotationReader.
236
     *
237
     * @return Reader
238
     */
239 3
    public function getAnnotationReader()
240
    {
241 3
        if ($this->AnnotationReader) {
242
            return $this->AnnotationReader;
243
        }
244
245 3
        return new \Doctrine\Common\Annotations\AnnotationReader();
246
    }
247
248
    /**
249
     * Convert to Entity of Identity value to associative array.
250
     *
251
     * @param AbstractEntity $Entity
252
     *
253
     * @return array associative array of [[id => value], [id => value], ...]
254
     */
255 3
    public function getEntityIdentifierAsArray(AbstractEntity $Entity)
256
    {
257 3
        $Result = [];
258 3
        $PropReflect = new \ReflectionClass($Entity);
259 3
        if ($Entity instanceof Proxy) {
260
            // Doctrine Proxy の場合は親クラスを取得
261
            $PropReflect = $PropReflect->getParentClass();
262
        }
263 3
        $Properties = $PropReflect->getProperties();
264
265 3
        foreach ($Properties as $Property) {
266 3
            $anno = $this->getAnnotationReader()->getPropertyAnnotation($Property, Id::class);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $anno is correct as $this->getAnnotationRead...\ORM\Mapping\Id::class) (which targets Doctrine\Common\Annotati...getPropertyAnnotation()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
267 3
            if ($anno) {
268 3
                $Property->setAccessible(true);
269 3
                $Result[$Property->getName()] = $Property->getValue($Entity);
270
            }
271
        }
272
273 3
        return $Result;
274
    }
275
}
276