1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* 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\InstantiatorInterface; |
14
|
|
|
use Spiral\ODM\ODMInterface; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Provides ability to construct Document and DocumentEntities with inheritance support. |
18
|
|
|
*/ |
19
|
|
|
class DocumentInstantiator implements InstantiatorInterface |
20
|
|
|
{ |
21
|
|
|
/** |
22
|
|
|
* @invisible |
23
|
|
|
* @var ODMInterface |
24
|
|
|
*/ |
25
|
|
|
private $odm; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Primary instantiation class. |
29
|
|
|
* |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
private $class = ''; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Normalized schema delivered by DocumentSchema. |
36
|
|
|
* |
37
|
|
|
* @var array |
38
|
|
|
*/ |
39
|
|
|
private $schema = []; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param ODMInterface $odm |
43
|
|
|
* @param string $class |
44
|
|
|
* @param array $schema |
45
|
|
|
*/ |
46
|
|
|
public function __construct(ODMInterface $odm, string $class, array $schema) |
47
|
|
|
{ |
48
|
|
|
$this->odm = $odm; |
49
|
|
|
$this->class = $class; |
50
|
|
|
$this->schema = $schema; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @param array|\ArrayAccess $fields |
55
|
|
|
* |
56
|
|
|
* @return CompositableInterface|DocumentEntity|Document |
57
|
|
|
*/ |
58
|
|
|
public function instantiate($fields): CompositableInterface |
59
|
|
|
{ |
60
|
|
|
$class = $this->defineClass($fields); |
61
|
|
|
|
62
|
|
|
if ($class !== $this->class) { |
63
|
|
|
//We have to dedicate class creation to external instantiator (possibly children class) |
64
|
|
|
return $this->odm->instantiate($class, $fields); |
|
|
|
|
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
//Now we can construct needed class, in this case we are following DocumentEntity declaration |
68
|
|
|
return new $class($fields, $this->schema, $this->odm); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Define document class using it's fieldset and definition. |
73
|
|
|
* |
74
|
|
|
* @param \ArrayAccess|array $fields |
75
|
|
|
* |
76
|
|
|
* @return string |
77
|
|
|
* |
78
|
|
|
* @throws DefinitionException |
79
|
|
|
*/ |
80
|
|
|
protected function defineClass($fields) |
81
|
|
|
{ |
82
|
|
|
//Rule to define class instance |
83
|
|
|
$definition = $this->schema[DocumentEntity::SH_INSTANTIATION]; |
84
|
|
|
|
85
|
|
|
if (is_string($definition)) { |
86
|
|
|
//Document has no variations |
87
|
|
|
return $definition; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
if (!is_array($fields)) { |
91
|
|
|
//Unable to resolve for non array set, using same class as given |
92
|
|
|
return $this->class; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
$defined = $this->class; |
96
|
|
|
foreach ($definition as $field => $child) { |
97
|
|
|
if (array_key_exists($field, $fields)) { |
98
|
|
|
//Apparently this is child |
99
|
|
|
$defined = $child; |
100
|
|
|
break; |
101
|
|
|
} |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
return $defined; |
105
|
|
|
} |
106
|
|
|
} |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.