Completed
Push — 4.0 ( 268f2c...88f012 )
by Hideki
05:48 queued 10s
created

src/Eccube/Entity/AbstractEntity.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Util\StringUtil;
23
use Symfony\Component\Serializer\Encoder\XmlEncoder;
24
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
25
use Symfony\Component\Serializer\Serializer;
26
27
/** @MappedSuperclass */
28
abstract class AbstractEntity implements \ArrayAccess
29
{
30
    private $AnnotationReader;
31
32 325
    public function offsetExists($offset)
33
    {
34 325
        $method = Inflector::classify($offset);
35
36 325
        return method_exists($this, $method)
37 325
            || method_exists($this, "get$method")
38 325
            || method_exists($this, "is$method")
39 325
            || method_exists($this, "has$method");
40
    }
41
42
    public function offsetSet($offset, $value)
43
    {
44
    }
45
46 332
    public function offsetGet($offset)
47
    {
48 332
        $method = Inflector::classify($offset);
49
50 332
        if (method_exists($this, $method)) {
51 92
            return $this->$method();
52 332
        } elseif (method_exists($this, "get$method")) {
53 319
            return $this->{"get$method"}();
54 172
        } elseif (method_exists($this, "is$method")) {
55 171
            return $this->{"is$method"}();
56 70
        } elseif (method_exists($this, "has$method")) {
57
            return $this->{"has$method"}();
58
        }
59
    }
60
61
    public function offsetUnset($offset)
62
    {
63
    }
64
65
    /**
66
     * 引数の連想配列を元にプロパティを設定します.
67
     * DBから取り出した連想配列を, プロパティへ設定する際に使用します.
68
     *
69
     * @param array $arrProps プロパティの情報を格納した連想配列
70
     * @param \ReflectionClass $parentClass 親のクラス. 本メソッドの内部的に使用します.
71
     * @param string[] $excludeAttribute 除外したいフィールド名の配列
72
     */
73 240
    public function setPropertiesFromArray(array $arrProps, array $excludeAttribute = [], \ReflectionClass $parentClass = null)
74
    {
75 240
        $objReflect = null;
76 240
        if (is_object($parentClass)) {
77 240
            $objReflect = $parentClass;
78
        } else {
79 240
            $objReflect = new \ReflectionClass($this);
80
        }
81 240
        $arrProperties = $objReflect->getProperties();
82 240 View Code Duplication
        foreach ($arrProperties as $objProperty) {
83 240
            $objProperty->setAccessible(true);
84 240
            $name = $objProperty->getName();
85 240
            if (in_array($name, $excludeAttribute) || !array_key_exists($name, $arrProps)) {
86 240
                continue;
87
            }
88 240
            $objProperty->setValue($this, $arrProps[$name]);
89
        }
90
91
        // 親クラスがある場合は再帰的にプロパティを取得
92 240
        $parentClass = $objReflect->getParentClass();
93 240
        if (is_object($parentClass)) {
94 240
            self::setPropertiesFromArray($arrProps, $excludeAttribute, $parentClass);
95
        }
96
    }
97
98
    /**
99
     * Convert to associative array.
100
     *
101
     * Symfony Serializer Component is expensive, and hard to implementation.
102
     * Use for encoder only.
103
     *
104
     * @param \ReflectionClass $parentClass parent class. Use internally of this method..
105
     * @param array $excludeAttribute Array of field names to exclusion.
106
     *
107
     * @return array
108
     */
109 474
    public function toArray(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'], \ReflectionClass $parentClass = null)
110
    {
111 474
        $objReflect = null;
112 474
        if (is_object($parentClass)) {
113 474
            $objReflect = $parentClass;
114
        } else {
115 474
            $objReflect = new \ReflectionClass($this);
116
        }
117 474
        $arrProperties = $objReflect->getProperties();
118 474
        $arrResults = [];
119 474 View Code Duplication
        foreach ($arrProperties as $objProperty) {
120 474
            $objProperty->setAccessible(true);
121 474
            $name = $objProperty->getName();
122 474
            if (in_array($name, $excludeAttribute)) {
123 473
                continue;
124
            }
125 474
            $arrResults[$name] = $objProperty->getValue($this);
126
        }
127
128 474
        $parentClass = $objReflect->getParentClass();
129 474
        if (is_object($parentClass)) {
130 474
            $arrParents = self::toArray($excludeAttribute, $parentClass);
131 474
            if (!is_array($arrParents)) {
132
                $arrParents = [];
133
            }
134 474
            if (!is_array($arrResults)) {
135
                $arrResults = [];
136
            }
137 474
            $arrResults = array_merge($arrParents, $arrResults);
138
        }
139
140 474
        return $arrResults;
141
    }
142
143
    /**
144
     * Convert to associative array, and normalize to association properties.
145
     *
146
     * The type conversion such as:
147
     * - Datetime ::  W3C datetime format string
148
     * - AbstractEntity :: associative array such as [id => value]
149
     * - PersistentCollection :: associative array of [[id => value], [id => value], ...]
150
     *
151
     * @param array $excludeAttribute Array of field names to exclusion.
152
     *
153
     * @return array
154
     */
155 3
    public function toNormalizedArray(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'])
156
    {
157 3
        $arrResult = $this->toArray($excludeAttribute);
158 3
        foreach ($arrResult as &$value) {
159 3
            if ($value instanceof \DateTime) {
160
                // see also https://stackoverflow.com/a/17390817/4956633
161 3
                $value->setTimezone(new \DateTimeZone('UTC'));
162 3
                $value = $value->format('Y-m-d\TH:i:s\Z');
163 3
            } elseif ($value instanceof AbstractEntity) {
164
                // Entity の場合は [id => value] の配列を返す
165
                $value = $this->getEntityIdentifierAsArray($value);
166 3
            } elseif ($value instanceof Collection) {
167
                // Collection の場合は ID を持つオブジェクトの配列を返す
168 3
                $Collections = $value;
169 3
                $value = [];
170 3
                foreach ($Collections as $Child) {
171 3
                    $value[] = $this->getEntityIdentifierAsArray($Child);
172
                }
173
            }
174
        }
175
176 3
        return $arrResult;
177
    }
178
179
    /**
180
     * Convert to JSON.
181
     *
182
     * @param array $excludeAttribute Array of field names to exclusion.
183
     *
184
     * @return string
185
     */
186 1
    public function toJSON(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'])
187
    {
188 1
        return json_encode($this->toNormalizedArray($excludeAttribute));
189
    }
190
191
    /**
192
     * Convert to XML.
193
     *
194
     * @param array $excludeAttribute Array of field names to exclusion.
195
     *
196
     * @return string
197
     */
198 1
    public function toXML(array $excludeAttribute = ['__initializer__', '__cloner__', '__isInitialized__', 'AnnotationReader'])
199
    {
200 1
        $ReflectionClass = new \ReflectionClass($this);
201 1
        $serializer = new Serializer([new PropertyNormalizer()], [new XmlEncoder($ReflectionClass->getShortName())]);
202
203 1
        $xml = $serializer->serialize($this->toNormalizedArray($excludeAttribute), 'xml');
204 1
        if ('\\' === DIRECTORY_SEPARATOR) {
205
            // The m modifier of the preg functions converts the end-of-line to '\n'
206
            $xml = StringUtil::convertLineFeed($xml, "\r\n");
207
        }
208 1
209
        return $xml;
210
    }
211
212
    /**
213
     * コピー元のオブジェクトのフィールド名を指定して、同名のフィールドに値をコピー
214
     *
215
     * @param object $srcObject コピー元のオブジェクト
216
     * @param string[] $excludeAttribute 除外したいフィールド名の配列
217
     *
218
     * @return AbstractEntity
219 209
     */
220
    public function copyProperties($srcObject, array $excludeAttribute = [])
221 209
    {
222
        $this->setPropertiesFromArray($srcObject->toArray($excludeAttribute), $excludeAttribute);
223 209
224
        return $this;
225
    }
226
227
    /**
228
     * Set AnnotationReader.
229
     *
230
     * @param Reader $Reader
231
     *
232
     * @return AbstractEntity
233 1020
     */
234
    public function setAnnotationReader(Reader $Reader)
235 1020
    {
236
        $this->AnnotationReader = $Reader;
237 1020
238
        return $this;
239
    }
240
241
    /**
242
     * Get AnnotationReader.
243
     *
244
     * @return Reader
245 3
     */
246
    public function getAnnotationReader()
247 3
    {
248
        if ($this->AnnotationReader) {
249
            return $this->AnnotationReader;
250
        }
251 3
252
        return new \Doctrine\Common\Annotations\AnnotationReader();
253
    }
254
255
    /**
256
     * Convert to Entity of Identity value to associative array.
257
     *
258
     * @param AbstractEntity $Entity
259
     *
260
     * @return array associative array of [[id => value], [id => value], ...]
261 3
     */
262
    public function getEntityIdentifierAsArray(AbstractEntity $Entity)
263 3
    {
264 3
        $Result = [];
265 3
        $PropReflect = new \ReflectionClass($Entity);
266
        if ($Entity instanceof Proxy) {
267
            // Doctrine Proxy の場合は親クラスを取得
268
            $PropReflect = $PropReflect->getParentClass();
269 3
        }
270
        $Properties = $PropReflect->getProperties();
271 3
272 3
        foreach ($Properties as $Property) {
273 3
            $anno = $this->getAnnotationReader()->getPropertyAnnotation($Property, Id::class);
0 ignored issues
show
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...
274 3
            if ($anno) {
275 3
                $Property->setAccessible(true);
276
                $Result[$Property->getName()] = $Property->getValue($Entity);
277
            }
278
        }
279 3
280
        return $Result;
281
    }
282
}
283