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; |
|
|
|
|
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; |
|
|
|
|
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())]); |
|
|
|
|
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); |
|
|
|
|
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
|
|
|
|
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
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.