Completed
Pull Request — master (#1803)
by Maciej
15:54
created

DocumentRepository::createAggregationBuilder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Repository;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Criteria;
9
use Doctrine\Common\Collections\Selectable;
10
use Doctrine\Common\Persistence\ObjectRepository;
11
use Doctrine\ODM\MongoDB\Aggregation\Builder as AggregationBuilder;
12
use Doctrine\ODM\MongoDB\DocumentManager;
13
use Doctrine\ODM\MongoDB\Iterator\Iterator;
14
use Doctrine\ODM\MongoDB\LockException;
15
use Doctrine\ODM\MongoDB\LockMode;
16
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
17
use Doctrine\ODM\MongoDB\Mapping\MappingException;
18
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
19
use Doctrine\ODM\MongoDB\Query\Builder as QueryBuilder;
20
use Doctrine\ODM\MongoDB\Query\QueryExpressionVisitor;
21
use Doctrine\ODM\MongoDB\UnitOfWork;
22
use function count;
23
use function is_array;
24
25
/**
26
 * A DocumentRepository serves as a repository for documents with generic as well as
27
 * business specific methods for retrieving documents.
28
 *
29
 * This class is designed for inheritance and users can subclass this class to
30
 * write their own repositories with business-specific methods to locate documents.
31
 */
32
class DocumentRepository implements ObjectRepository, Selectable
33
{
34
    /** @var string */
35
    protected $documentName;
36
37
    /** @var DocumentManager */
38
    protected $dm;
39
40
    /** @var UnitOfWork */
41
    protected $uow;
42
43
    /** @var ClassMetadata */
44
    protected $class;
45
46
    /**
47
     * Initializes this instance with the specified document manager, unit of work and
48
     * class metadata.
49
     *
50
     * @param DocumentManager $dm            The DocumentManager to use.
51
     * @param UnitOfWork      $uow           The UnitOfWork to use.
52
     * @param ClassMetadata   $classMetadata The class metadata.
53
     */
54 356
    public function __construct(DocumentManager $dm, UnitOfWork $uow, ClassMetadata $classMetadata)
55
    {
56 356
        $this->documentName = $classMetadata->name;
57 356
        $this->dm           = $dm;
58 356
        $this->uow          = $uow;
59 356
        $this->class        = $classMetadata;
60 356
    }
61
62
    /**
63
     * Creates a new Query\Builder instance that is preconfigured for this document name.
64
     */
65 15
    public function createQueryBuilder() : QueryBuilder
66
    {
67 15
        return $this->dm->createQueryBuilder($this->documentName);
68
    }
69
70
    /**
71
     * Creates a new Aggregation\Builder instance that is prepopulated for this document name.
72
     */
73
    public function createAggregationBuilder() : AggregationBuilder
74
    {
75
        return $this->dm->createAggregationBuilder($this->documentName);
76
    }
77
78
    /**
79
     * Clears the repository, causing all managed documents to become detached.
80
     */
81
    public function clear() : void
82
    {
83
        $this->dm->clear($this->class->rootDocumentName);
84
    }
85
86
    /**
87
     * Finds a document matching the specified identifier. Optionally a lock mode and
88
     * expected version may be specified.
89
     *
90
     * @param mixed $id Identifier.
91
     *
92
     * @throws MappingException
93
     * @throws LockException
94
     */
95 249
    public function find($id, int $lockMode = LockMode::NONE, ?int $lockVersion = null) : ?object
96
    {
97 249
        if ($id === null) {
98
            return null;
99
        }
100
101
        /* TODO: What if the ID object has a field with the same name as the
102
         * class' mapped identifier field name?
103
         */
104 249
        if (is_array($id)) {
105 2
            [$identifierFieldName] = $this->class->getIdentifierFieldNames();
0 ignored issues
show
Bug introduced by
The variable $identifierFieldName does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
106
107 2
            if (isset($id[$identifierFieldName])) {
108
                $id = $id[$identifierFieldName];
109
            }
110
        }
111
112
        // Check identity map first
113 249
        $document = $this->uow->tryGetById($id, $this->class);
114 249
        if ($document) {
115 21
            if ($lockMode !== LockMode::NONE) {
116
                $this->dm->lock($document, $lockMode, $lockVersion);
117
            }
118
119 21
            return $document; // Hit!
120
        }
121
122 242
        $criteria = ['_id' => $id];
123
124 242
        if ($lockMode === LockMode::NONE) {
125 242
            return $this->getDocumentPersister()->load($criteria);
126
        }
127
128
        if ($lockMode === LockMode::OPTIMISTIC) {
129
            if (! $this->class->isVersioned) {
130
                throw LockException::notVersioned($this->documentName);
131
            }
132
133
            $document = $this->getDocumentPersister()->load($criteria);
134
            if ($document) {
135
                $this->uow->lock($document, $lockMode, $lockVersion);
136
            }
137
138
            return $document;
139
        }
140
141
        return $this->getDocumentPersister()->load($criteria, null, [], $lockMode);
142
    }
143
144
    /**
145
     * Finds all documents in the repository.
146
     */
147 10
    public function findAll() : array
148
    {
149 10
        return $this->findBy([]);
150
    }
151
152
    /**
153
     * Finds documents by a set of criteria.
154
     *
155
     * @param int|null $limit
156
     * @param int|null $skip
157
     */
158 11
    public function findBy(array $criteria, ?array $sort = null, $limit = null, $skip = null) : array
159
    {
160 11
        return $this->getDocumentPersister()->loadAll($criteria, $sort, $limit, $skip)->toArray();
161
    }
162
163
    /**
164
     * Finds a single document by a set of criteria.
165
     */
166 84
    public function findOneBy(array $criteria) : ?object
167
    {
168 84
        return $this->getDocumentPersister()->load($criteria);
169
    }
170
171 8
    public function getDocumentName() : string
172
    {
173 8
        return $this->documentName;
174
    }
175
176
    public function getDocumentManager() : DocumentManager
177
    {
178
        return $this->dm;
179
    }
180
181
    public function getClassMetadata() : ClassMetadata
182
    {
183
        return $this->class;
184
    }
185
186 8
    public function getClassName() : string
187
    {
188 8
        return $this->getDocumentName();
189
    }
190
191
    /**
192
     * Selects all elements from a selectable that match the expression and
193
     * returns a new collection containing these elements.
194
     *
195
     * @see Selectable::matching()
196
     */
197 4
    public function matching(Criteria $criteria) : ArrayCollection
198
    {
199 4
        $visitor      = new QueryExpressionVisitor($this->createQueryBuilder());
200 4
        $queryBuilder = $this->createQueryBuilder();
201
202 4
        if ($criteria->getWhereExpression() !== null) {
203 1
            $expr = $visitor->dispatch($criteria->getWhereExpression());
204 1
            $queryBuilder->setQueryArray($expr->getQuery());
205
        }
206
207 4
        if ($criteria->getMaxResults() !== null) {
208
            $queryBuilder->limit($criteria->getMaxResults());
209
        }
210
211 4
        if ($criteria->getFirstResult() !== null) {
212
            $queryBuilder->skip($criteria->getFirstResult());
213
        }
214
215 4
        if (count($criteria->getOrderings())) {
216
            $queryBuilder->sort($criteria->getOrderings());
217
        }
218
219
        // @TODO: wrap around a specialized Collection for efficient count on large collections
220 4
        $iterator = $queryBuilder->getQuery()->execute();
221 4
        assert($iterator instanceof Iterator);
222 4
        return new ArrayCollection($iterator->toArray());
223
    }
224
225 334
    protected function getDocumentPersister() : DocumentPersister
226
    {
227 334
        return $this->uow->getDocumentPersister($this->documentName);
228
    }
229
}
230