RecordSource::setSelector()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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