Completed
Pull Request — master (#1654)
by Andreas
10:38
created

Lookup::prepareFieldName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
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\Aggregation\Stage;
21
22
use Doctrine\Common\Persistence\Mapping\MappingException as BaseMappingException;
23
use Doctrine\MongoDB\Aggregation\Stage as BaseStage;
24
use Doctrine\ODM\MongoDB\Aggregation\Builder;
25
use Doctrine\ODM\MongoDB\DocumentManager;
26
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
27
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
28
use Doctrine\ODM\MongoDB\Mapping\MappingException;
29
30
/**
31
 * Fluent interface for building aggregation pipelines.
32
 */
33
class Lookup extends BaseStage\Lookup
34
{
35
    /**
36
     * @var DocumentManager
37
     */
38
    private $dm;
39
40
    /**
41
     * @var ClassMetadata
42
     */
43
    private $class;
44
45
    /**
46
     * @var ClassMetadata
47
     */
48
    private $targetClass;
49
50
    /**
51
     * @param Builder $builder
52
     * @param string $from
53
     * @param DocumentManager $documentManager
54
     * @param ClassMetadata $class
55
     */
56 13
    public function __construct(Builder $builder, $from, DocumentManager $documentManager, ClassMetadata $class)
57
    {
58 13
        $this->dm = $documentManager;
59 13
        $this->class = $class;
60
61 13
        parent::__construct($builder, $from);
62 11
    }
63
64
    /**
65
     * @param string $from
66
     * @return $this
67
     */
68 13 View Code Duplication
    public function from($from)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
    {
70
        // $from can either be
71
        // a) a field name indicating a reference to a different document. Currently, only REFERENCE_STORE_AS_ID is supported
72
        // b) a Class name
73
        // c) a collection name
74
        // In cases b) and c) the local and foreign fields need to be filled
75 13
        if ($this->class->hasReference($from)) {
76 9
            return $this->fromReference($from);
77
        }
78
79
        // Check if mapped class with given name exists
80
        try {
81 4
            $this->targetClass = $this->dm->getClassMetadata($from);
82 1
        } catch (BaseMappingException $e) {
83 1
            return parent::from($from);
84
        }
85
86 3
        if ($this->targetClass->isSharded()) {
87 1
            throw MappingException::cannotUseShardedCollectionInLookupStages($this->targetClass->name);
88
        }
89
90 2
        return parent::from($this->targetClass->getCollection());
91
    }
92
93
    /**
94
     * @param string $fieldName
95
     * @return $this
96
     * @throws MappingException
97
     */
98 9
    private function fromReference($fieldName)
99
    {
100 9
        if (! $this->class->hasReference($fieldName)) {
101
            MappingException::referenceMappingNotFound($this->class->name, $fieldName);
102
        }
103
104 9
        $referenceMapping = $this->class->getFieldMapping($fieldName);
105 9
        $this->targetClass = $this->dm->getClassMetadata($referenceMapping['targetDocument']);
106 9
        if ($this->targetClass->isSharded()) {
107 1
            throw MappingException::cannotUseShardedCollectionInLookupStages($this->targetClass->name);
108
        }
109
110 8
        parent::from($this->targetClass->getCollection());
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (from() instead of fromReference()). Are you sure this is correct? If so, you might want to change this to $this->from().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
111
112 8
        if ($referenceMapping['isOwningSide']) {
113 4 View Code Duplication
            switch ($referenceMapping['storeAs']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
114 4
                case ClassMetadataInfo::REFERENCE_STORE_AS_ID:
115 1
                case ClassMetadataInfo::REFERENCE_STORE_AS_REF:
116 4
                    $referencedFieldName = ClassMetadataInfo::getReferenceFieldName($referenceMapping['storeAs'], $referenceMapping['name']);
117 4
                    break;
118
119
                default:
120
                   throw MappingException::cannotLookupDbRefReference($this->class->name, $fieldName);
121
            }
122
123
            $this
124 4
                ->foreignField('_id')
125 4
                ->localField($referencedFieldName);
126
        } else {
127 4 View Code Duplication
            if (isset($referenceMapping['repositoryMethod']) || ! isset($referenceMapping['mappedBy'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
                throw MappingException::repositoryMethodLookupNotAllowed($this->class->name, $fieldName);
129
            }
130
131 4
            $mappedByMapping = $this->targetClass->getFieldMapping($referenceMapping['mappedBy']);
132 4 View Code Duplication
            switch ($mappedByMapping['storeAs']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
133 4
                case ClassMetadataInfo::REFERENCE_STORE_AS_ID:
134 2
                case ClassMetadataInfo::REFERENCE_STORE_AS_REF:
135 4
                    $referencedFieldName = ClassMetadataInfo::getReferenceFieldName($mappedByMapping['storeAs'], $mappedByMapping['name']);
136 4
                    break;
137
138
                default:
139
                    throw MappingException::cannotLookupDbRefReference($this->class->name, $fieldName);
140
            }
141
142
            $this
143 4
                ->localField('_id')
144 4
                ->foreignField($referencedFieldName);
145
        }
146
147 8
        return $this;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 11
    public function localField($localField)
154
    {
155 11
        return parent::localField($this->prepareFieldName($localField, $this->class));
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161 11
    public function foreignField($foreignField)
162
    {
163 11
        return parent::foreignField($this->prepareFieldName($foreignField, $this->targetClass));
164
    }
165
166 11
    protected function prepareFieldName($fieldName, ClassMetadata $class = null)
167
    {
168 11
        if ( ! $class) {
169 1
            return $fieldName;
170
        }
171
172 11
        return $this->getDocumentPersister($class)->prepareFieldName($fieldName);
173
    }
174
175
    /**
176
     * @return \Doctrine\ODM\MongoDB\Persisters\DocumentPersister
177
     */
178 11
    private function getDocumentPersister(ClassMetadata $class)
179
    {
180 11
        return $this->dm->getUnitOfWork()->getDocumentPersister($class->name);
181
    }
182
}
183