Completed
Branch feature/pre-split (0400ca)
by Anton
03:49
created

DocumentInstantiator::normalizeFields()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 2
nop 1
dl 12
loc 12
rs 9.4285
c 0
b 0
f 0
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
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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
}