Completed
Branch feature/pre-split (a42d1e)
by Anton
03:22
created

DocumentEntity::withODM()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ODM;
8
9
use Spiral\Core\Component;
10
use Spiral\Core\Exceptions\ScopeException;
11
use Spiral\Core\Traits\SaturateTrait;
12
use Spiral\Models\AccessorInterface;
13
use Spiral\Models\SchematicEntity;
14
use Spiral\Models\Traits\SolidStateTrait;
15
use Spiral\ODM\Entities\DocumentInstantiator;
16
17
/**
18
 * Primary class for spiral ODM, provides ability to pack it's own updates in a form of atomic
19
 * updates.
20
 *
21
 * You can use same properties to configure entity as in DataEntity + schema property.
22
 *
23
 * Example:
24
 *
25
 * class Test extends DocumentEntity
26
 * {
27
 *    const SCHEMA = [
28
 *       'name' => 'string'
29
 *    ];
30
 * }
31
 *
32
 * Configuration properties:
33
 * - schema
34
 * - defaults
35
 * - secured (* by default)
36
 * - fillable
37
 */
38
abstract class DocumentEntity extends SchematicEntity implements CompositableInterface
39
{
40
    use SaturateTrait, SolidStateTrait;
41
42
    /**
43
     * Set of schema sections needed to describe entity behaviour.
44
     */
45
    const SH_INSTANTIATION = 0;
46
    const SH_DEFAULTS      = 1;
47
    const SH_COMPOSITIONS  = 6;
48
    const SH_AGGREGATIONS  = 7;
49
50
    /**
51
     * Constants used to describe aggregation relations (also used internally to identify
52
     * composition).
53
     *
54
     * Example:
55
     * 'items' => [self::MANY => Item::class, ['parentID' => 'key::_id']]
56
     *
57
     * @see DocumentEntity::SCHEMA
58
     */
59
    const MANY = 778;
60
    const ONE  = 899;
61
62
    /**
63
     * Class responsible for instance construction.
64
     */
65
    const INSTANTIATOR = DocumentInstantiator::class;
66
67
    /**
68
     * Document fields, accessors and relations. ODM will generate setters and getters for some
69
     * fields based on their types.
70
     *
71
     * Example, fields:
72
     * const SCHEMA = [
73
     *      '_id'    => 'MongoId', //Primary key field
74
     *      'value'  => 'string',  //Default string field
75
     *      'values' => ['string'] //ScalarArray accessor will be applied for fields like that
76
     * ];
77
     *
78
     * Compositions:
79
     * const SCHEMA = [
80
     *     ...,
81
     *     'child'       => Child::class,   //One document are composited, for example user Profile
82
     *     'many'        => [Child::class]  //Compositor accessor will be applied, allows to
83
     *                                      //composite many document instances
84
     * ];
85
     *
86
     * Documents can extend each other, in this case schema will also be inherited.
87
     *
88
     * @var array
89
     */
90
    const SCHEMA = [];
91
92
    /**
93
     * Default field values.
94
     *
95
     * @var array
96
     */
97
    const DEFAULTS = [];
98
99
    /**
100
     * Model behaviour configurations.
101
     */
102
    const SECURED   = '*';
103
    const HIDDEN    = [];
104
    const FILLABLE  = [];
105
    const SETTERS   = [];
106
    const GETTERS   = [];
107
    const ACCESSORS = [];
108
109
    /**
110
     * Document behaviour schema.
111
     *
112
     * @var array
113
     */
114
    private $schema = [];
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
115
116
    /**
117
     * Parent ODM instance, responsible for aggregations and lazy loading operations.
118
     *
119
     * @invisible
120
     * @var ODMInterface
121
     */
122
    protected $odm;
123
124
    /**
125
     * {@inheritdoc}
126
     *
127
     * @param ODMInterface $odm To lazy create nested document ang aggregations.
128
     *
129
     * @throws ScopeException When no ODM instance can be resolved.
130
     */
131
    public function __construct($fields = [], array $schema = null, ODMInterface $odm = null)
132
    {
133
        //We can use global container as fallback if no default values were provided
134
        $this->odm = $this->saturate($odm, ODMInterface::class);
135
136
        //Use supplied schema or fetch one from ODM
137
        $this->schema = !empty($schema) ? $schema : $this->odm->define(
138
            static::class,
139
            ODMInterface::D_SCHEMA
140
        );
141
142
        $fields = is_array($fields) ? $fields : [];
143
        if (!empty($this->schema[self::SH_DEFAULTS])) {
144
            //Merging with default values
145
            $fields = array_replace_recursive($this->schema[self::SH_DEFAULTS], $fields);
146
        }
147
148
        parent::__construct($fields, $this->schema);
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function hasUpdates(): bool
155
    {
156
        return false;
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function buildAtomics(string $container = ''): array
163
    {
164
        // TODO: Implement buildAtomics() method.
165
        return [];
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171
    public function flushUpdates()
172
    {
173
        //todo: do flush
174
175
        // TODO: Implement flushUpdates() method.
176
    }
177
178
    /**
179
     * @return array
180
     */
181
    public function __debugInfo()
182
    {
183
        return [
184
            'fields'  => $this->getFields(),
185
            'atomics' => $this->hasUpdates() ? $this->buildAtomics() : []
186
        ];
187
    }
188
189
    /**
190
     * {@inheritdoc}
191
     */
192
    protected function iocContainer()
193
    {
194
        if (!empty($this->odm) || $this->odm instanceof Component) {
195
            //Forwarding IoC scope to parent ODM instance
196
            return $this->odm->iocContainer();
197
        }
198
199
        return parent::iocContainer();
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     *
205
     * DocumentEntity will pass ODM instance as part of accessor context.
206
     */
207
    protected function createAccessor(string $accessor, string $field, $value): AccessorInterface
208
    {
209
        //Field as a context
210
        return new $accessor($value, ['field' => $field, 'entity' => $this, 'odm' => $this->odm]);
211
    }
212
}