Completed
Push — master ( a8fe50...bce26f )
by Maciej
13s
created

ODM/MongoDB/Repository/DocumentRepository.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\LockException;
14
use Doctrine\ODM\MongoDB\LockMode;
15
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
16
use Doctrine\ODM\MongoDB\Mapping\MappingException;
17
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
18
use Doctrine\ODM\MongoDB\Query\Builder as QueryBuilder;
19
use Doctrine\ODM\MongoDB\Query\QueryExpressionVisitor;
20
use Doctrine\ODM\MongoDB\UnitOfWork;
21
use function is_array;
22
23
/**
24
 * A DocumentRepository serves as a repository for documents with generic as well as
25
 * business specific methods for retrieving documents.
26
 *
27
 * This class is designed for inheritance and users can subclass this class to
28
 * write their own repositories with business-specific methods to locate documents.
29
 *
30
 */
31
class DocumentRepository implements ObjectRepository, Selectable
32
{
33
    /** @var string */
34
    protected $documentName;
35
36
    /** @var DocumentManager */
37
    protected $dm;
38
39
    /** @var UnitOfWork */
40
    protected $uow;
41
42
    /** @var ClassMetadata */
43
    protected $class;
44
45
    /**
46
     * Initializes this instance with the specified document manager, unit of work and
47
     * class metadata.
48
     *
49
     * @param DocumentManager $dm            The DocumentManager to use.
50
     * @param UnitOfWork      $uow           The UnitOfWork to use.
51
     * @param ClassMetadata   $classMetadata The class metadata.
52
     */
53 357
    public function __construct(DocumentManager $dm, UnitOfWork $uow, ClassMetadata $classMetadata)
54
    {
55 357
        $this->documentName = $classMetadata->name;
56 357
        $this->dm = $dm;
57 357
        $this->uow = $uow;
58 357
        $this->class = $classMetadata;
59 357
    }
60
61
    /**
62
     * Creates a new Query\Builder instance that is preconfigured for this document name.
63
     */
64 16
    public function createQueryBuilder(): QueryBuilder
65
    {
66 16
        return $this->dm->createQueryBuilder($this->documentName);
67
    }
68
69
    /**
70
     * Creates a new Aggregation\Builder instance that is prepopulated for this document name.
71
     */
72
    public function createAggregationBuilder(): AggregationBuilder
73
    {
74
        return $this->dm->createAggregationBuilder($this->documentName);
75
    }
76
77
    /**
78
     * Clears the repository, causing all managed documents to become detached.
79
     */
80
    public function clear(): void
81
    {
82
        $this->dm->clear($this->class->rootDocumentName);
83
    }
84
85
    /**
86
     * Finds a document matching the specified identifier. Optionally a lock mode and
87
     * expected version may be specified.
88
     *
89
     * @param mixed $id Identifier.
90
     * @throws MappingException
91
     * @throws LockException
92
     */
93 250
    public function find($id, int $lockMode = LockMode::NONE, ?int $lockVersion = null): ?object
94
    {
95 250
        if ($id === null) {
96
            return null;
97
        }
98
99
        /* TODO: What if the ID object has a field with the same name as the
100
         * class' mapped identifier field name?
101
         */
102 250
        if (is_array($id)) {
103 2
            list($identifierFieldName) = $this->class->getIdentifierFieldNames();
104
105 2
            if (isset($id[$identifierFieldName])) {
106
                $id = $id[$identifierFieldName];
107
            }
108
        }
109
110
        // Check identity map first
111 250
        $document = $this->uow->tryGetById($id, $this->class);
112 250
        if ($document) {
113 22
            if ($lockMode !== LockMode::NONE) {
114
                $this->dm->lock($document, $lockMode, $lockVersion);
115
            }
116
117 22
            return $document; // Hit!
118
        }
119
120 243
        $criteria = ['_id' => $id];
121
122 243
        if ($lockMode === LockMode::NONE) {
123 243
            return $this->getDocumentPersister()->load($criteria);
124
        }
125
126
        if ($lockMode === LockMode::OPTIMISTIC) {
127
            if (! $this->class->isVersioned) {
128
                throw LockException::notVersioned($this->documentName);
129
            }
130
131
            $document = $this->getDocumentPersister()->load($criteria);
132
            if ($document) {
133
                $this->uow->lock($document, $lockMode, $lockVersion);
134
            }
135
136
            return $document;
137
        }
138
139
        return $this->getDocumentPersister()->load($criteria, null, [], $lockMode);
140
    }
141
142
    /**
143
     * Finds all documents in the repository.
144
     */
145 10
    public function findAll(): array
146
    {
147 10
        return $this->findBy([]);
148
    }
149
150
    /**
151
     * Finds documents by a set of criteria.
152
     *
153
     * @param int|null $limit
154
     * @param int|null $offset
155
     */
156 11
    public function findBy(array $criteria, ?array $sort = null, $limit = null, $skip = null): array
157
    {
158 11
        return $this->getDocumentPersister()->loadAll($criteria, $sort, $limit, $skip)->toArray(false);
0 ignored issues
show
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...
159
    }
160
161
    /**
162
     * Finds a single document by a set of criteria.
163
     */
164 84
    public function findOneBy(array $criteria): ?object
165
    {
166 84
        return $this->getDocumentPersister()->load($criteria);
167
    }
168
169 8
    public function getDocumentName(): string
170
    {
171 8
        return $this->documentName;
172
    }
173
174
    public function getDocumentManager(): DocumentManager
175
    {
176
        return $this->dm;
177
    }
178
179
    public function getClassMetadata(): ClassMetadata
180
    {
181
        return $this->class;
182
    }
183
184 8
    public function getClassName(): string
185
    {
186 8
        return $this->getDocumentName();
187
    }
188
189
    /**
190
     * Selects all elements from a selectable that match the expression and
191
     * returns a new collection containing these elements.
192
     *
193
     * @see Selectable::matching()
194
     */
195 4
    public function matching(Criteria $criteria): ArrayCollection
196
    {
197 4
        $visitor = new QueryExpressionVisitor($this->createQueryBuilder());
198 4
        $queryBuilder = $this->createQueryBuilder();
199
200 4
        if ($criteria->getWhereExpression() !== null) {
201 1
            $expr = $visitor->dispatch($criteria->getWhereExpression());
202 1
            $queryBuilder->setQueryArray($expr->getQuery());
203
        }
204
205 4
        if ($criteria->getMaxResults() !== null) {
206
            $queryBuilder->limit($criteria->getMaxResults());
207
        }
208
209 4
        if ($criteria->getFirstResult() !== null) {
210
            $queryBuilder->skip($criteria->getFirstResult());
211
        }
212
213 4
        if ($criteria->getOrderings() !== null) {
214 4
            $queryBuilder->sort($criteria->getOrderings());
215
        }
216
217
        // @TODO: wrap around a specialized Collection for efficient count on large collections
218 4
        return new ArrayCollection($queryBuilder->getQuery()->execute()->toArray());
219
    }
220
221 335
    protected function getDocumentPersister(): DocumentPersister
222
    {
223 335
        return $this->uow->getDocumentPersister($this->documentName);
224
    }
225
}
226