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\Aggregation\Stage; |
||
6 | |||
7 | use Doctrine\Common\Persistence\Mapping\MappingException as BaseMappingException; |
||
8 | use Doctrine\ODM\MongoDB\Aggregation\Builder; |
||
9 | use Doctrine\ODM\MongoDB\Aggregation\Stage; |
||
10 | use Doctrine\ODM\MongoDB\DocumentManager; |
||
11 | use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; |
||
12 | use Doctrine\ODM\MongoDB\Mapping\MappingException; |
||
13 | use Doctrine\ODM\MongoDB\Persisters\DocumentPersister; |
||
14 | |||
15 | /** |
||
16 | * Fluent interface for building aggregation pipelines. |
||
17 | */ |
||
18 | class Lookup extends Stage |
||
19 | { |
||
20 | /** @var DocumentManager */ |
||
21 | private $dm; |
||
22 | |||
23 | /** @var ClassMetadata */ |
||
24 | private $class; |
||
25 | |||
26 | /** @var ClassMetadata */ |
||
27 | private $targetClass; |
||
28 | |||
29 | /** @var string */ |
||
30 | private $from; |
||
31 | |||
32 | /** @var string */ |
||
33 | private $localField; |
||
34 | |||
35 | /** @var string */ |
||
36 | private $foreignField; |
||
37 | |||
38 | /** @var string */ |
||
39 | private $as; |
||
40 | |||
41 | 14 | public function __construct(Builder $builder, string $from, DocumentManager $documentManager, ClassMetadata $class) |
|
42 | { |
||
43 | 14 | parent::__construct($builder); |
|
44 | |||
45 | 14 | $this->dm = $documentManager; |
|
46 | 14 | $this->class = $class; |
|
47 | |||
48 | 14 | $this->from($from); |
|
49 | 12 | } |
|
50 | |||
51 | /** |
||
52 | * Specifies the name of the new array field to add to the input documents. |
||
53 | * |
||
54 | * The new array field contains the matching documents from the from |
||
55 | * collection. If the specified name already exists in the input document, |
||
56 | * the existing field is overwritten. |
||
57 | */ |
||
58 | 12 | public function alias(string $alias) : self |
|
59 | { |
||
60 | 12 | $this->as = $alias; |
|
61 | |||
62 | 12 | return $this; |
|
63 | } |
||
64 | |||
65 | /** |
||
66 | * Specifies the collection or field name in the same database to perform the join with. |
||
67 | * |
||
68 | * The from collection cannot be sharded. |
||
69 | */ |
||
70 | 14 | public function from(string $from) : self |
|
71 | { |
||
72 | // $from can either be |
||
73 | // a) a field name indicating a reference to a different document. Currently, only REFERENCE_STORE_AS_ID is supported |
||
74 | // b) a Class name |
||
75 | // c) a collection name |
||
76 | // In cases b) and c) the local and foreign fields need to be filled |
||
77 | 14 | if ($this->class->hasReference($from)) { |
|
78 | 9 | return $this->fromReference($from); |
|
79 | } |
||
80 | |||
81 | // Check if mapped class with given name exists |
||
82 | try { |
||
83 | 5 | $this->targetClass = $this->dm->getClassMetadata($from); |
|
84 | 2 | } catch (BaseMappingException $e) { |
|
0 ignored issues
–
show
|
|||
85 | 2 | $this->from = $from; |
|
86 | 2 | return $this; |
|
87 | } |
||
88 | |||
89 | 3 | if ($this->targetClass->isSharded()) { |
|
90 | 1 | throw MappingException::cannotUseShardedCollectionInLookupStages($this->targetClass->name); |
|
91 | } |
||
92 | |||
93 | 2 | $this->from = $this->targetClass->getCollection(); |
|
94 | 2 | return $this; |
|
95 | } |
||
96 | |||
97 | /** |
||
98 | * {@inheritdoc} |
||
99 | */ |
||
100 | 12 | public function getExpression() : array |
|
101 | { |
||
102 | return [ |
||
103 | '$lookup' => [ |
||
104 | 12 | 'from' => $this->from, |
|
105 | 12 | 'localField' => $this->localField, |
|
106 | 12 | 'foreignField' => $this->foreignField, |
|
107 | 12 | 'as' => $this->as, |
|
108 | ], |
||
109 | ]; |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Specifies the field from the documents input to the $lookup stage. |
||
114 | * |
||
115 | * $lookup performs an equality match on the localField to the foreignField |
||
116 | * from the documents of the from collection. If an input document does not |
||
117 | * contain the localField, the $lookup treats the field as having a value of |
||
118 | * null for matching purposes. |
||
119 | */ |
||
120 | 12 | public function localField(string $localField) : self |
|
121 | { |
||
122 | 12 | $this->localField = $this->prepareFieldName($localField, $this->class); |
|
123 | 12 | return $this; |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * Specifies the field from the documents in the from collection. |
||
128 | * |
||
129 | * $lookup performs an equality match on the foreignField to the localField |
||
130 | * from the input documents. If a document in the from collection does not |
||
131 | * contain the foreignField, the $lookup treats the value as null for |
||
132 | * matching purposes. |
||
133 | */ |
||
134 | 12 | public function foreignField(string $foreignField) : self |
|
135 | { |
||
136 | 12 | $this->foreignField = $this->prepareFieldName($foreignField, $this->targetClass); |
|
137 | 12 | return $this; |
|
138 | } |
||
139 | |||
140 | 12 | protected function prepareFieldName(string $fieldName, ?ClassMetadata $class = null) : string |
|
141 | { |
||
142 | 12 | if (! $class) { |
|
143 | 2 | return $fieldName; |
|
144 | } |
||
145 | |||
146 | 12 | return $this->getDocumentPersister($class)->prepareFieldName($fieldName); |
|
147 | } |
||
148 | |||
149 | /** |
||
150 | * @throws MappingException |
||
151 | */ |
||
152 | 9 | private function fromReference(string $fieldName) : self |
|
153 | { |
||
154 | 9 | if (! $this->class->hasReference($fieldName)) { |
|
155 | MappingException::referenceMappingNotFound($this->class->name, $fieldName); |
||
156 | } |
||
157 | |||
158 | 9 | $referenceMapping = $this->class->getFieldMapping($fieldName); |
|
159 | 9 | $this->targetClass = $this->dm->getClassMetadata($referenceMapping['targetDocument']); |
|
160 | 9 | if ($this->targetClass->isSharded()) { |
|
161 | 1 | throw MappingException::cannotUseShardedCollectionInLookupStages($this->targetClass->name); |
|
162 | } |
||
163 | |||
164 | 8 | $this->from = $this->targetClass->getCollection(); |
|
165 | |||
166 | 8 | if ($referenceMapping['isOwningSide']) { |
|
167 | 4 | switch ($referenceMapping['storeAs']) { |
|
168 | case ClassMetadata::REFERENCE_STORE_AS_ID: |
||
169 | case ClassMetadata::REFERENCE_STORE_AS_REF: |
||
170 | 4 | $referencedFieldName = ClassMetadata::getReferenceFieldName($referenceMapping['storeAs'], $referenceMapping['name']); |
|
171 | 4 | break; |
|
172 | |||
173 | default: |
||
174 | throw MappingException::cannotLookupDbRefReference($this->class->name, $fieldName); |
||
175 | } |
||
176 | |||
177 | $this |
||
178 | 4 | ->foreignField('_id') |
|
179 | 4 | ->localField($referencedFieldName); |
|
180 | } else { |
||
181 | 4 | if (isset($referenceMapping['repositoryMethod']) || ! isset($referenceMapping['mappedBy'])) { |
|
182 | throw MappingException::repositoryMethodLookupNotAllowed($this->class->name, $fieldName); |
||
183 | } |
||
184 | |||
185 | 4 | $mappedByMapping = $this->targetClass->getFieldMapping($referenceMapping['mappedBy']); |
|
186 | 4 | switch ($mappedByMapping['storeAs']) { |
|
187 | case ClassMetadata::REFERENCE_STORE_AS_ID: |
||
188 | case ClassMetadata::REFERENCE_STORE_AS_REF: |
||
189 | 4 | $referencedFieldName = ClassMetadata::getReferenceFieldName($mappedByMapping['storeAs'], $mappedByMapping['name']); |
|
190 | 4 | break; |
|
191 | |||
192 | default: |
||
193 | throw MappingException::cannotLookupDbRefReference($this->class->name, $fieldName); |
||
194 | } |
||
195 | |||
196 | $this |
||
197 | 4 | ->localField('_id') |
|
198 | 4 | ->foreignField($referencedFieldName); |
|
199 | } |
||
200 | |||
201 | 8 | return $this; |
|
202 | } |
||
203 | |||
204 | 12 | private function getDocumentPersister(ClassMetadata $class) : DocumentPersister |
|
205 | { |
||
206 | 12 | return $this->dm->getUnitOfWork()->getDocumentPersister($class->name); |
|
207 | } |
||
208 | } |
||
209 |
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.