Failed Conditions
Pull Request — 4.0 (#4528)
by Kentaro
07:39
created

AbstractEntity::toArray()   B

Complexity

Conditions 7
Paths 30

Size

Total Lines 33

Duplication

Lines 8
Ratio 24.24 %

Code Coverage

Tests 20
CRAP Score 7.0368

Importance

Changes 0
Metric Value
cc 7
nc 30
nop 2
dl 8
loc 33
ccs 20
cts 22
cp 0.9091
crap 7.0368
rs 8.4586
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.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\Id;
20
use Doctrine\ORM\Mapping\MappedSuperclass;
21
use Doctrine\ORM\Proxy\Proxy;
22
use Eccube\DependencyInjection\Facade\AnnotationReaderFacade;
23
use Eccube\Util\StringUtil;
24
use Symfony\Component\Serializer\Encoder\XmlEncoder;
25
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
26
use Symfony\Component\Serializer\Serializer;
27
28
/** @MappedSuperclass */
29
abstract class AbstractEntity implements \ArrayAccess
30
{
31
    public function offsetExists($offset)
32 325
    {
33
        $method = Inflector::classify($offset);
34 325
35
        return method_exists($this, $method)
36 325
            || method_exists($this, "get$method")
37 325
            || method_exists($this, "is$method")
38 325
            || method_exists($this, "has$method");
39 325
    }
40
41
    public function offsetSet($offset, $value)
42
    {
43
    }
44
45
    public function offsetGet($offset)
46 332
    {
47
        $method = Inflector::classify($offset);
48 332
49
        if (method_exists($this, $method)) {
50 332
            return $this->$method();
51 92
        } elseif (method_exists($this, "get$method")) {
52 332
            return $this->{"get$method"}();
53 319
        } elseif (method_exists($this, "is$method")) {
54 172
            return $this->{"is$method"}();
55 171
        } elseif (method_exists($this, "has$method")) {
56 70
            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
    public function setPropertiesFromArray(array $arrProps, array $excludeAttribute = [], \ReflectionClass $parentClass = null)
73 240
    {
74
        $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 240
        if (is_object($parentClass)) {
76 240
            $objReflect = $parentClass;
77 240
        } else {
78
            $objReflect = new \ReflectionClass($this);
79 240
        }
80
        $arrProperties = $objReflect->getProperties();
81 240 View Code Duplication
        foreach ($arrProperties as $objProperty) {
82 240
            $objProperty->setAccessible(true);
83 240
            $name = $objProperty->getName();
84 240
            if (in_array($name, $excludeAttribute) || !array_key_exists($name, $arrProps)) {
85 240
                continue;
86 240
            }
87
            $objProperty->setValue($this, $arrProps[$name]);
88 240
        }
89
90
        // 親クラスがある場合は再帰的にプロパティを取得
91
        $parentClass = $objReflect->getParentClass();
92 240
        if (is_object($parentClass)) {
93 240
            self::setPropertiesFromArray($arrProps, $excludeAttribute, $parentClass);
94 240
        }
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
    public function toArray(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__'], \ReflectionClass $parentClass = null)
109 474
    {
110
        $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 474
        if (is_object($parentClass)) {
112 474
            $objReflect = $parentClass;
113 474
        } else {
114
            $objReflect = new \ReflectionClass($this);
115 474
        }
116
        $arrProperties = $objReflect->getProperties();
117 474
        $arrResults = [];
118 474 View Code Duplication
        foreach ($arrProperties as $objProperty) {
119 474
            $objProperty->setAccessible(true);
120 474
            $name = $objProperty->getName();
121 474
            if (in_array($name, $excludeAttribute)) {
122 474
                continue;
123 473
            }
124
            $arrResults[$name] = $objProperty->getValue($this);
125 474
        }
126
127
        $parentClass = $objReflect->getParentClass();
128 474
        if (is_object($parentClass)) {
129 474
            $arrParents = self::toArray($excludeAttribute, $parentClass);
130 474
            if (!is_array($arrParents)) {
131 474
                $arrParents = [];
132
            }
133
            if (!is_array($arrResults)) {
134 474
                $arrResults = [];
135
            }
136
            $arrResults = array_merge($arrParents, $arrResults);
137 474
        }
138
139
        return $arrResults;
140 474
    }
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
    public function toNormalizedArray(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__'])
155 3
    {
156
        $arrResult = $this->toArray($excludeAttribute);
157 3
        foreach ($arrResult as &$value) {
158 3
            if ($value instanceof \DateTime) {
159 3
                // see also https://stackoverflow.com/a/17390817/4956633
160
                $value->setTimezone(new \DateTimeZone('UTC'));
161 3
                $value = $value->format('Y-m-d\TH:i:s\Z');
162 3
            } elseif ($value instanceof AbstractEntity) {
163 3
                // Entity の場合は [id => value] の配列を返す
164
                $value = $this->getEntityIdentifierAsArray($value);
165
            } elseif ($value instanceof Collection) {
166 3
                // Collection の場合は ID を持つオブジェクトの配列を返す
167
                $Collections = $value;
168 3
                $value = [];
169 3
                foreach ($Collections as $Child) {
170 3
                    $value[] = $this->getEntityIdentifierAsArray($Child);
171 3
                }
172
            }
173
        }
174
175
        return $arrResult;
176 3
    }
177
178
    /**
179
     * Convert to JSON.
180
     *
181
     * @param array $excludeAttribute Array of field names to exclusion.
182
     *
183
     * @return string
184
     */
185
    public function toJSON(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__'])
186 1
    {
187
        return json_encode($this->toNormalizedArray($excludeAttribute));
188 1
    }
189
190
    /**
191
     * Convert to XML.
192
     *
193
     * @param array $excludeAttribute Array of field names to exclusion.
194
     *
195
     * @return string
196
     */
197
    public function toXML(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__'])
198 1
    {
199
        $ReflectionClass = new \ReflectionClass($this);
200 1
        $serializer = new Serializer([new PropertyNormalizer()], [new XmlEncoder($ReflectionClass->getShortName())]);
0 ignored issues
show
Documentation introduced by
$ReflectionClass->getShortName() is of type string, but the function expects a array.

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...
201 1
202
        $xml = $serializer->serialize($this->toNormalizedArray($excludeAttribute), 'xml');
203 1
        if ('\\' === DIRECTORY_SEPARATOR) {
204 1
            // The m modifier of the preg functions converts the end-of-line to '\n'
205
            $xml = StringUtil::convertLineFeed($xml, "\r\n");
206
        }
207
208 1
        return $xml;
209
    }
210
211
    /**
212
     * コピー元のオブジェクトのフィールド名を指定して、同名のフィールドに値をコピー
213
     *
214
     * @param object $srcObject コピー元のオブジェクト
215
     * @param string[] $excludeAttribute 除外したいフィールド名の配列
216
     *
217
     * @return AbstractEntity
218
     */
219 209
    public function copyProperties($srcObject, array $excludeAttribute = [])
220
    {
221 209
        $this->setPropertiesFromArray($srcObject->toArray($excludeAttribute), $excludeAttribute);
222
223 209
        return $this;
224
    }
225
226
    /**
227
     * Convert to Entity of Identity value to associative array.
228
     *
229
     * @param AbstractEntity $Entity
230
     *
231
     * @return array associative array of [[id => value], [id => value], ...]
232
     */
233 1020
    public function getEntityIdentifierAsArray(AbstractEntity $Entity)
234
    {
235 1020
        $Result = [];
236
        $PropReflect = new \ReflectionClass($Entity);
237 1020
        if ($Entity instanceof Proxy) {
238
            // Doctrine Proxy の場合は親クラスを取得
239
            $PropReflect = $PropReflect->getParentClass();
240
        }
241
        $Properties = $PropReflect->getProperties();
242
243
        foreach ($Properties as $Property) {
244
            $AnnotationReader = AnnotationReaderFacade::create();
245 3
            $anno = $AnnotationReader->getPropertyAnnotation($Property, Id::class);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $anno is correct as $AnnotationReader->getPr...\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...
246
            if ($anno) {
247 3
                $Property->setAccessible(true);
248
                $Result[$Property->getName()] = $Property->getValue($Entity);
249
            }
250
        }
251 3
252
        return $Result;
253
    }
254
}
255