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

DocumentSource::getSelector()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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