Completed
Pull Request — master (#1803)
by Maciej
18:23 queued 15:20
created

DocumentRepository   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 58.46%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 9
dl 0
loc 224
ccs 38
cts 65
cp 0.5846
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A createQueryBuilder() 0 4 1
A createAggregationBuilder() 0 4 1
A clear() 0 4 1
C find() 0 48 10
A findAll() 0 4 1
A findBy() 0 4 1
A findOneBy() 0 4 1
A getDocumentName() 0 4 1
A getDocumentManager() 0 4 1
A getClassMetadata() 0 4 1
A getClassName() 0 4 1
B matching() 0 25 5
A getDocumentPersister() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB;
6
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Doctrine\Common\Collections\Criteria;
10
use Doctrine\Common\Collections\Selectable;
11
use Doctrine\Common\Persistence\ObjectRepository;
12
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
13
use Doctrine\ODM\MongoDB\Query\QueryExpressionVisitor;
14
use function count;
15
use function is_array;
16
17
/**
18
 * A DocumentRepository serves as a repository for documents with generic as well as
19
 * business specific methods for retrieving documents.
20
 *
21
 * This class is designed for inheritance and users can subclass this class to
22
 * write their own repositories with business-specific methods to locate documents.
23
 *
24
 */
25
class DocumentRepository implements ObjectRepository, Selectable
26
{
27
    /** @var string */
28
    protected $documentName;
29
30
    /** @var DocumentManager */
31
    protected $dm;
32
33
    /** @var UnitOfWork */
34
    protected $uow;
35
36
    /** @var ClassMetadata */
37
    protected $class;
38
39
    /**
40
     * Initializes this instance with the specified document manager, unit of work and
41
     * class metadata.
42
     *
43
     * @param DocumentManager $dm            The DocumentManager to use.
44
     * @param UnitOfWork      $uow           The UnitOfWork to use.
45
     * @param ClassMetadata   $classMetadata The class metadata.
46
     */
47 327
    public function __construct(DocumentManager $dm, UnitOfWork $uow, ClassMetadata $classMetadata)
48
    {
49 327
        $this->documentName = $classMetadata->name;
50 327
        $this->dm = $dm;
51 327
        $this->uow = $uow;
52 327
        $this->class = $classMetadata;
53 327
    }
54
55
    /**
56
     * Creates a new Query\Builder instance that is preconfigured for this document name.
57
     *
58
     * @return Query\Builder $qb
59
     */
60 16
    public function createQueryBuilder()
61
    {
62 16
        return $this->dm->createQueryBuilder($this->documentName);
63
    }
64
65
    /**
66
     * Creates a new Aggregation\Builder instance that is prepopulated for this document name.
67
     *
68
     * @return Aggregation\Builder
69
     */
70
    public function createAggregationBuilder()
71
    {
72
        return $this->dm->createAggregationBuilder($this->documentName);
73
    }
74
75
    /**
76
     * Clears the repository, causing all managed documents to become detached.
77
     */
78
    public function clear()
79
    {
80
        $this->dm->clear($this->class->rootDocumentName);
81
    }
82
83
    /**
84
     * Finds a document matching the specified identifier. Optionally a lock mode and
85
     * expected version may be specified.
86
     *
87
     * @param mixed $id          Identifier.
88
     * @param int   $lockMode    Optional. Lock mode; one of the LockMode constants.
89
     * @param int   $lockVersion Optional. Expected version.
90
     * @throws Mapping\MappingException
91
     * @throws LockException
92
     * @return object|null The document, if found, otherwise null.
93
     */
94 233
    public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
95
    {
96 233
        if ($id === null) {
97
            return null;
98
        }
99
100
        /* TODO: What if the ID object has a field with the same name as the
101
         * class' mapped identifier field name?
102
         */
103 233
        if (is_array($id)) {
104 2
            list($identifierFieldName) = $this->class->getIdentifierFieldNames();
105
106 2
            if (isset($id[$identifierFieldName])) {
107
                $id = $id[$identifierFieldName];
108
            }
109
        }
110
111
        // Check identity map first
112 233
        $document = $this->uow->tryGetById($id, $this->class);
113 233
        if ($document) {
114 21
            if ($lockMode !== LockMode::NONE) {
115
                $this->dm->lock($document, $lockMode, $lockVersion);
116
            }
117
118 21
            return $document; // Hit!
119
        }
120
121 227
        $criteria = ['_id' => $id];
122
123 227
        if ($lockMode === LockMode::NONE) {
124 227
            return $this->getDocumentPersister()->load($criteria);
125
        }
126
127
        if ($lockMode === LockMode::OPTIMISTIC) {
128
            if (! $this->class->isVersioned) {
129
                throw LockException::notVersioned($this->documentName);
130
            }
131
132
            $document = $this->getDocumentPersister()->load($criteria);
133
            if ($document) {
134
                $this->uow->lock($document, $lockMode, $lockVersion);
135
            }
136
137
            return $document;
138
        }
139
140
        return $this->getDocumentPersister()->load($criteria, null, [], $lockMode);
141
    }
142
143
    /**
144
     * Finds all documents in the repository.
145
     *
146
     * @return array
147
     */
148 10
    public function findAll()
149
    {
150 10
        return $this->findBy([]);
151
    }
152
153
    /**
154
     * Finds documents by a set of criteria.
155
     *
156
     * @param array    $criteria Query criteria
157
     * @param array    $sort     Sort array for Cursor::sort()
158
     * @param int|null $limit    Limit for Cursor::limit()
159
     * @param int|null $skip     Skip for Cursor::skip()
160
     *
161
     * @return array
162
     */
163 11
    public function findBy(array $criteria, ?array $sort = null, $limit = null, $skip = null)
164
    {
165 11
        return $this->getDocumentPersister()->loadAll($criteria, $sort, $limit, $skip)->toArray(false);
0 ignored issues
show
Unused Code introduced by
The call to Iterator::toArray() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
166
    }
167
168
    /**
169
     * Finds a single document by a set of criteria.
170
     *
171
     * @param array $criteria
172
     * @return object
173
     */
174 74
    public function findOneBy(array $criteria)
175
    {
176 74
        return $this->getDocumentPersister()->load($criteria);
177
    }
178
179
    /**
180
     * @return string
181
     */
182
    public function getDocumentName()
183
    {
184
        return $this->documentName;
185
    }
186
187
    /**
188
     * @return DocumentManager
189
     */
190
    public function getDocumentManager()
191
    {
192
        return $this->dm;
193
    }
194
195
    /**
196
     * @return Mapping\ClassMetadata
197
     */
198
    public function getClassMetadata()
199
    {
200
        return $this->class;
201
    }
202
203
    /**
204
     * @return string
205
     */
206
    public function getClassName()
207
    {
208
        return $this->getDocumentName();
209
    }
210
211
    /**
212
     * Selects all elements from a selectable that match the expression and
213
     * returns a new collection containing these elements.
214
     *
215
     * @see Selectable::matching()
216
     * @return Collection
217
     */
218 4
    public function matching(Criteria $criteria)
219
    {
220 4
        $visitor = new QueryExpressionVisitor($this->createQueryBuilder());
221 4
        $queryBuilder = $this->createQueryBuilder();
222
223 4
        if ($criteria->getWhereExpression() !== null) {
224 1
            $expr = $visitor->dispatch($criteria->getWhereExpression());
225 1
            $queryBuilder->setQueryArray($expr->getQuery());
226
        }
227
228 4
        if ($criteria->getMaxResults() !== null) {
229
            $queryBuilder->limit($criteria->getMaxResults());
230
        }
231
232 4
        if ($criteria->getFirstResult() !== null) {
233
            $queryBuilder->skip($criteria->getFirstResult());
234
        }
235
236 4
        if (count($criteria->getOrderings())) {
237
            $queryBuilder->sort($criteria->getOrderings());
238
        }
239
240
        // @TODO: wrap around a specialized Collection for efficient count on large collections
241 4
        return new ArrayCollection($queryBuilder->getQuery()->execute()->toArray());
242
    }
243
244 309
    protected function getDocumentPersister()
245
    {
246 309
        return $this->uow->getDocumentPersister($this->documentName);
247
    }
248
}
249