|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Spiral Framework, Core Components |
|
4
|
|
|
* |
|
5
|
|
|
* @author Wolfy-J |
|
6
|
|
|
*/ |
|
7
|
|
|
namespace Spiral\ODM\Entities; |
|
8
|
|
|
|
|
9
|
|
|
use Spiral\ODM\CompositableInterface; |
|
10
|
|
|
use Spiral\ODM\Document; |
|
11
|
|
|
use Spiral\ODM\DocumentEntity; |
|
12
|
|
|
use Spiral\ODM\Exceptions\DefinitionException; |
|
13
|
|
|
use Spiral\ODM\Exceptions\InstantionException; |
|
14
|
|
|
use Spiral\ODM\InstantiatorInterface; |
|
15
|
|
|
use Spiral\ODM\ODMInterface; |
|
16
|
|
|
|
|
17
|
|
|
/** |
|
18
|
|
|
* Provides ability to construct Document and DocumentEntities with inheritance support. |
|
19
|
|
|
*/ |
|
20
|
|
|
class DocumentInstantiator implements InstantiatorInterface |
|
21
|
|
|
{ |
|
22
|
|
|
/** |
|
23
|
|
|
* @invisible |
|
24
|
|
|
* @var ODMInterface |
|
25
|
|
|
*/ |
|
26
|
|
|
private $odm; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* Primary instantiation class. |
|
30
|
|
|
* |
|
31
|
|
|
* @var string |
|
32
|
|
|
*/ |
|
33
|
|
|
private $class = ''; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* Normalized schema delivered by DocumentSchema. |
|
37
|
|
|
* |
|
38
|
|
|
* @var array |
|
39
|
|
|
*/ |
|
40
|
|
|
private $schema = []; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @param ODMInterface $odm |
|
44
|
|
|
* @param string $class |
|
45
|
|
|
* @param array $schema |
|
46
|
|
|
*/ |
|
47
|
|
|
public function __construct(ODMInterface $odm, string $class, array $schema) |
|
48
|
|
|
{ |
|
49
|
|
|
$this->odm = $odm; |
|
50
|
|
|
$this->class = $class; |
|
51
|
|
|
$this->schema = $schema; |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* {@inheritdoc} |
|
56
|
|
|
* |
|
57
|
|
|
* @return CompositableInterface|DocumentEntity|Document |
|
58
|
|
|
* |
|
59
|
|
|
* @throws InstantionException |
|
60
|
|
|
*/ |
|
61
|
|
|
public function instantiate($fields, bool $filter = true): CompositableInterface |
|
62
|
|
|
{ |
|
63
|
|
|
$class = $this->defineClass($fields); |
|
64
|
|
|
|
|
65
|
|
|
if ($class !== $this->class) { |
|
66
|
|
|
//We have to dedicate class creation to external instantiator (possibly children class) |
|
67
|
|
|
return $this->odm->instantiate($class, $fields, $filter); |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
if (!is_array($fields)) { |
|
71
|
|
|
$fields = $this->normalizeFields($fields); |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
//Now we can construct needed class, in this case we are following DocumentEntity declaration |
|
75
|
|
|
if (!$filter) { |
|
76
|
|
|
//No need to filter values, passing directly in constructor |
|
77
|
|
|
return new $class($fields, $this->schema, $this->odm); |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
$entity = new $class($fields, $this->schema, $this->odm); |
|
81
|
|
|
if (!$entity instanceof CompositableInterface) { |
|
82
|
|
|
throw new InstantionException( |
|
83
|
|
|
"Unable to set filtered values for {$class}, must be instance of CompositableInterface" |
|
84
|
|
|
); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
//Must pass value thought all needed filters |
|
88
|
|
|
$entity->stateValue($fields); |
|
89
|
|
|
|
|
90
|
|
|
return $entity; |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* Define document class using it's fieldset and definition. |
|
95
|
|
|
* |
|
96
|
|
|
* @param \ArrayAccess|array $fields |
|
97
|
|
|
* |
|
98
|
|
|
* @return string |
|
99
|
|
|
* |
|
100
|
|
|
* @throws DefinitionException |
|
101
|
|
|
*/ |
|
102
|
|
|
protected function defineClass($fields) |
|
103
|
|
|
{ |
|
104
|
|
|
//Rule to define class instance |
|
105
|
|
|
$definition = $this->schema[DocumentEntity::SH_INSTANTIATION]; |
|
106
|
|
|
|
|
107
|
|
|
if (is_string($definition)) { |
|
108
|
|
|
//Document has no variations |
|
109
|
|
|
return $definition; |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
if (!is_array($fields)) { |
|
113
|
|
|
//Unable to resolve for non array set, using same class as given |
|
114
|
|
|
return $this->class; |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
$defined = $this->class; |
|
118
|
|
|
foreach ($definition as $field => $child) { |
|
119
|
|
|
if (array_key_exists($field, $fields)) { |
|
120
|
|
|
//Apparently this is child |
|
121
|
|
|
$defined = $child; |
|
122
|
|
|
break; |
|
123
|
|
|
} |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
return $defined; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* @param \Traversable|\ArrayAccess $fields |
|
131
|
|
|
* |
|
132
|
|
|
* @return array |
|
133
|
|
|
*/ |
|
134
|
|
View Code Duplication |
private function normalizeFields($fields): array |
|
|
|
|
|
|
135
|
|
|
{ |
|
136
|
|
|
$result = []; |
|
137
|
|
|
if (!is_scalar($fields)) { |
|
138
|
|
|
//Trying to iterate over |
|
139
|
|
|
foreach ($fields as $name => $value) { |
|
140
|
|
|
$result[$name] = $value; |
|
141
|
|
|
} |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
return $result; |
|
145
|
|
|
} |
|
146
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.