DocumentSource::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 2
1
<?php
2
/**
3
 * Spiral, Core Components
4
 *
5
 * @author Wolfy-J
6
 */
7
8
namespace Spiral\ODM\Entities;
9
10
use Spiral\Core\Component;
11
use Spiral\Core\Traits\SaturateTrait;
12
use Spiral\ODM\CompositableInterface;
13
use Spiral\ODM\Document;
14
use Spiral\ODM\Exceptions\SourceException;
15
use Spiral\ODM\ODM;
16
use Spiral\ODM\ODMInterface;
17
18
/**
19
 * Source class associated to one or multiple (default implementation) ODM models. Source can be
20
 * used to write your own custom find method or change default selection.
21
 */
22
class DocumentSource extends Component implements \Countable, \IteratorAggregate
23
{
24
    use SaturateTrait;
25
26
    /**
27
     * Linked document model. ODM can automatically index and link user sources to models based on
28
     * value of this constant.
29
     *
30
     * Use this constant in custom source implementation in order to automatically link it to
31
     * appropriate model AND be able to create source as constructor or method injection without
32
     * ODM dependency.
33
     */
34
    const DOCUMENT = null;
35
36
    /**
37
     * @var DocumentSelector
38
     */
39
    private $selector;
40
41
    /**
42
     * Associated document class.
43
     *
44
     * @var string
45
     */
46
    private $class = null;
47
48
    /**
49
     * @invisible
50
     *
51
     * @var ODMInterface
52
     */
53
    protected $odm = null;
54
55
    /**
56
     * @param string       $class
57
     * @param ODMInterface $odm
58
     *
59
     * @throws SourceException
60
     */
61
    public function __construct(string $class = null, ODMInterface $odm = null)
62
    {
63
        if (empty($class)) {
64
            if (empty(static::DOCUMENT)) {
65
                throw new SourceException('Unable to create source without associated class');
66
            }
67
68
            $class = static::DOCUMENT;
69
        }
70
71
        $this->class = $class;
72
        $this->odm = $this->saturate($odm, ODMInterface::class);
73
    }
74
75
    /**
76
     * Associated class.
77
     *
78
     * @return string
79
     */
80
    public function getClass(): string
81
    {
82
        return $this->class;
83
    }
84
85
    /**
86
     * Create new DocumentEntity based on set of provided fields.
87
     *
88
     * @final Change static method of entity, not this one.
89
     *
90
     * @param array  $fields
91
     * @param string $class  Due ODM models can be inherited you can use this argument to specify
92
     *                       custom model class.
93
     *
94
     * @return CompositableInterface|Document
95
     */
96
    public function create($fields = [], string $class = null)
97
    {
98
        //Create model with filtered set of fields
99
        return $this->odm->make($class ?? $this->class, $fields, true);
100
    }
101
102
    /**
103
     * Find document by it's primary key.
104
     *
105
     * @see findOne()
106
     *
107
     * @param string|\MongoId $id Primary key value.
108
     *
109
     * @return CompositableInterface|Document|null
110
     */
111
    public function findByPK($id)
112
    {
113
        return $this->findOne(['_id' => ODM::mongoID($id)]);
114
    }
115
116
    /**
117
     * Select one document from mongo collection.
118
     *
119
     * @param array $query  Fields and conditions to query by.
120
     * @param array $sortBy Always specify sort by to ensure that results are stable.
121
     *
122
     * @return CompositableInterface|Document|null
123
     */
124
    public function findOne(array $query = [], array $sortBy = [])
125
    {
126
        return $this->getSelector()->sortBy($sortBy)->findOne($query);
127
    }
128
129
    /**
130
     * Get associated document selection with pre-configured query (if any).
131
     *
132
     * @param array $query
133
     *
134
     * @return DocumentSelector
135
     */
136
    public function find(array $query = []): DocumentSelector
137
    {
138
        return $this->getSelector()->where($query);
139
    }
140
141
    /**
142
     * @param array $query
143
     *
144
     * @return int
145
     */
146
    public function count(array $query = []): int
147
    {
148
        return $this->getSelector()->count($query);
149
    }
150
151
    /**
152
     * @return DocumentSelector
153
     */
154
    public function getIterator(): DocumentSelector
155
    {
156
        return $this->getSelector();
157
    }
158
159
    /**
160
     * Create source with new associated selector.
161
     *
162
     * @param DocumentSelector $selector
163
     *
164
     * @return DocumentSource
165
     */
166
    public function withSelector(DocumentSelector $selector): DocumentSource
167
    {
168
        $source = clone $this;
169
        $source->setSelector($selector);
170
171
        return $source;
172
    }
173
174
    /**
175
     * Set initial selector.
176
     *
177
     * @param DocumentSelector $selector
178
     */
179
    protected function setSelector(DocumentSelector $selector)
180
    {
181
        $this->selector = clone $selector;
182
    }
183
184
    /**
185
     * Get associated selector.
186
     *
187
     * @return DocumentSelector
188
     */
189
    protected function getSelector(): DocumentSelector
190
    {
191
        if (empty($this->selector)) {
192
            //Requesting selector on demand
193
            $this->selector = $this->odm->selector($this->class);
194
        }
195
196
        return clone $this->selector;
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202
    protected function iocContainer()
203
    {
204
        if ($this->odm instanceof Component) {
205
            //Always work in ODM scope
206
            return $this->odm->iocContainer();
207
        }
208
209
        return parent::iocContainer();
210
    }
211
}