DocumentInstantiator   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 3
dl 0
loc 112
rs 10
c 0
b 0
f 0

3 Methods

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