Completed
Push — master ( 73492b...2db3cf )
by Jeremy
11:56
created

DocumentRepository::clear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB;
21
22
use Doctrine\Common\Collections\ArrayCollection;
23
use Doctrine\Common\Collections\Collection;
24
use Doctrine\Common\Collections\Criteria;
25
use Doctrine\Common\Collections\Selectable;
26
use Doctrine\Common\Inflector\Inflector;
27
use Doctrine\Common\Persistence\ObjectRepository;
28
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
29
use Doctrine\ODM\MongoDB\Query\QueryExpressionVisitor;
30
31
/**
32
 * A DocumentRepository serves as a repository for documents with generic as well as
33
 * business specific methods for retrieving documents.
34
 *
35
 * This class is designed for inheritance and users can subclass this class to
36
 * write their own repositories with business-specific methods to locate documents.
37
 *
38
 * @since       1.0
39
 */
40
class DocumentRepository implements ObjectRepository, Selectable
41
{
42
    /**
43
     * @var string
44
     */
45
    protected $documentName;
46
47
    /**
48
     * @var DocumentManager
49
     */
50
    protected $dm;
51
52
    /**
53
     * @var UnitOfWork
54
     */
55
    protected $uow;
56
57
    /**
58
     * @var ClassMetadata
59
     */
60
    protected $class;
61
62
    /**
63
     * Initializes this instance with the specified document manager, unit of work and
64
     * class metadata.
65
     *
66
     * @param DocumentManager $dm The DocumentManager to use.
67
     * @param UnitOfWork $uow The UnitOfWork to use.
68
     * @param ClassMetadata $classMetadata The class metadata.
69
     */
70 365
    public function __construct(DocumentManager $dm, UnitOfWork $uow, ClassMetadata $classMetadata)
71
    {
72 365
        $this->documentName = $classMetadata->name;
73 365
        $this->dm = $dm;
74 365
        $this->uow = $uow;
75 365
        $this->class = $classMetadata;
76 365
    }
77
78
    /**
79
     * Creates a new Query\Builder instance that is preconfigured for this document name.
80
     *
81
     * @return Query\Builder $qb
82
     */
83 29
    public function createQueryBuilder()
84
    {
85 29
        return $this->dm->createQueryBuilder($this->documentName);
86
    }
87
88
    /**
89
     * Creates a new Aggregation\Builder instance that is prepopulated for this document name.
90
     *
91
     * @return Aggregation\Builder
92
     */
93
    public function createAggregationBuilder()
94
    {
95
        return $this->dm->createAggregationBuilder($this->documentName);
96
    }
97
98
    /**
99
     * Clears the repository, causing all managed documents to become detached.
100
     */
101
    public function clear()
102
    {
103
        $this->dm->clear($this->class->rootDocumentName);
104
    }
105
106
    /**
107
     * Finds a document matching the specified identifier. Optionally a lock mode and
108
     * expected version may be specified.
109
     *
110
     * @param mixed $id Identifier.
111
     * @param int $lockMode Optional. Lock mode; one of the LockMode constants.
112
     * @param int $lockVersion Optional. Expected version.
113
     * @throws Mapping\MappingException
114
     * @throws LockException
115
     * @return object|null The document, if found, otherwise null.
116
     */
117 252
    public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
118
    {
119 252
        if ($id === null) {
120
            return null;
121
        }
122
123
        /* TODO: What if the ID object has a field with the same name as the
124
         * class' mapped identifier field name?
125
         */
126 252
        if (is_array($id)) {
127 2
            list($identifierFieldName) = $this->class->getIdentifierFieldNames();
128
129 2
            if (isset($id[$identifierFieldName])) {
130
                $id = $id[$identifierFieldName];
131
            }
132
        }
133
134
        // Check identity map first
135 252
        if ($document = $this->uow->tryGetById($id, $this->class)) {
136 22
            if ($lockMode !== LockMode::NONE) {
137
                $this->dm->lock($document, $lockMode, $lockVersion);
138
            }
139
140 22
            return $document; // Hit!
141
        }
142
143 245
        $criteria = array('_id' => $id);
144
145 245
        if ($lockMode === LockMode::NONE) {
146 244
            return $this->getDocumentPersister()->load($criteria);
147
        }
148
149 1
        if ($lockMode === LockMode::OPTIMISTIC) {
150 1
            if (!$this->class->isVersioned) {
151
                throw LockException::notVersioned($this->documentName);
152
            }
153 1
            if ($document = $this->getDocumentPersister()->load($criteria)) {
154
                $this->uow->lock($document, $lockMode, $lockVersion);
155
            }
156
157 1
            return $document;
158
        }
159
160
        return $this->getDocumentPersister()->load($criteria, null, array(), $lockMode);
161
    }
162
163
    /**
164
     * Finds all documents in the repository.
165
     *
166
     * @return array
167
     */
168 11
    public function findAll()
169
    {
170 11
        return $this->findBy(array());
171
    }
172
173
    /**
174
     * Finds documents by a set of criteria.
175
     *
176
     * @param array        $criteria Query criteria
177
     * @param array        $sort     Sort array for Cursor::sort()
178
     * @param integer|null $limit    Limit for Cursor::limit()
179
     * @param integer|null $skip     Skip for Cursor::skip()
180
     *
181
     * @return array
182
     */
183 12
    public function findBy(array $criteria, array $sort = null, $limit = null, $skip = null)
184
    {
185 12
        return $this->getDocumentPersister()->loadAll($criteria, $sort, $limit, $skip)->toArray(false);
186
    }
187
188
    /**
189
     * Finds a single document by a set of criteria.
190
     *
191
     * @param array $criteria
192
     * @return object
193
     */
194 79
    public function findOneBy(array $criteria)
195
    {
196 79
        return $this->getDocumentPersister()->load($criteria);
197
    }
198
199
    /**
200
     * Adds support for magic finders.
201
     *
202
     * @param string $method
203
     * @param array $arguments
204
     * @throws MongoDBException
205
     * @throws \BadMethodCallException If the method called is an invalid find* method
206
     *                                 or no find* method at all and therefore an invalid
207
     *                                 method call.
208
     * @return array|object The found document/documents.
209
     */
210 10
    public function __call($method, $arguments)
211
    {
212 10
        if (strpos($method, 'findBy') === 0) {
213
            $by = substr($method, 6, strlen($method));
214
            $method = 'findBy';
215 10
        } elseif (strpos($method, 'findOneBy') === 0) {
216 10
            $by = substr($method, 9, strlen($method));
217 10
            $method = 'findOneBy';
218
        } else {
219
            throw new \BadMethodCallException(
220
                "Undefined method: '$method'. The method name must start with 'findBy' or 'findOneBy'!"
221
            );
222
        }
223
224 10
        if (!isset($arguments[0])) {
225
            throw MongoDBException::findByRequiresParameter($method . $by);
226
        }
227
228 10
        $fieldName = Inflector::camelize($by);
229
230 10
        if ($this->class->hasField($fieldName)) {
231 10
            return $this->$method(array($fieldName => $arguments[0]));
232
        } else {
233
            throw MongoDBException::invalidFindByCall($this->documentName, $fieldName, $method . $by);
234
        }
235
    }
236
237
    /**
238
     * @return string
239
     */
240
    public function getDocumentName()
241
    {
242
        return $this->documentName;
243
    }
244
245
    /**
246
     * @return DocumentManager
247
     */
248
    public function getDocumentManager()
249
    {
250
        return $this->dm;
251
    }
252
253
    /**
254
     * @return Mapping\ClassMetadata
255
     */
256
    public function getClassMetadata()
257
    {
258
        return $this->class;
259
    }
260
261
    /**
262
     * @return string
263
     */
264
    public function getClassName()
265
    {
266
        return $this->getDocumentName();
267
    }
268
269
    /**
270
     * Selects all elements from a selectable that match the expression and
271
     * returns a new collection containing these elements.
272
     *
273
     * @see Selectable::matching()
274
     * @param Criteria $criteria
275
     * @return Collection
276
     */
277 4
    public function matching(Criteria $criteria)
278
    {
279 4
        $visitor = new QueryExpressionVisitor($this->createQueryBuilder());
280 4
        $queryBuilder = $this->createQueryBuilder();
281
282 4
        if ($criteria->getWhereExpression() !== null) {
283 1
            $expr = $visitor->dispatch($criteria->getWhereExpression());
284 1
            $queryBuilder->setQueryArray($expr->getQuery());
285
        }
286
287 4
        if ($criteria->getMaxResults() !== null) {
288
            $queryBuilder->limit($criteria->getMaxResults());
289
        }
290
291 4
        if ($criteria->getFirstResult() !== null) {
292
            $queryBuilder->skip($criteria->getFirstResult());
293
        }
294
295 4
        if ($criteria->getOrderings() !== null) {
296 4
            $queryBuilder->sort($criteria->getOrderings());
297
        }
298
299
        // @TODO: wrap around a specialized Collection for efficient count on large collections
300 4
        return new ArrayCollection($queryBuilder->getQuery()->execute()->toArray(false));
301
    }
302
303 333
    protected function getDocumentPersister()
304
    {
305 333
        return $this->uow->getDocumentPersister($this->documentName);
306
    }
307
}
308