Failed Conditions
Pull Request — master (#6392)
by Alessandro
11:37
created

SingleTablePersister::getSelectConditionSQL()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 5
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\ORM\Persisters\Entity;
21
22
use Doctrine\ORM\Mapping\ClassMetadata;
23
use Doctrine\Common\Collections\Criteria;
24
use Doctrine\ORM\Utility\PersisterHelper;
25
26
/**
27
 * Persister for entities that participate in a hierarchy mapped with the
28
 * SINGLE_TABLE strategy.
29
 *
30
 * @author Roman Borschel <[email protected]>
31
 * @author Benjamin Eberlei <[email protected]>
32
 * @author Alexander <[email protected]>
33
 * @since 2.0
34
 * @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
35
 */
36
class SingleTablePersister extends AbstractEntityInheritancePersister
37
{
38
    /**
39
     * {@inheritdoc}
40
     */
41 176
    protected function getDiscriminatorColumnTableName()
42
    {
43 176
        return $this->class->getTableName();
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 42
    protected function getSelectColumnsSQL()
50
    {
51 42
        if ($this->currentPersisterContext->selectColumnListSql !== null) {
52 20
            return $this->currentPersisterContext->selectColumnListSql;
53
        }
54
55 42
        $columnList[] = parent::getSelectColumnsSQL();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$columnList was never initialized. Although not strictly required by PHP, it is generally a good practice to add $columnList = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
56
57 42
        $rootClass  = $this->em->getClassMetadata($this->class->rootEntityName);
58 42
        $tableAlias = $this->getSQLTableAlias($rootClass->name);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
59
60
         // Append discriminator column
61 42
        $discrColumn     = $this->class->discriminatorColumn['name'];
62 42
        $discrColumnType = $this->class->discriminatorColumn['type'];
63
64 42
        $columnList[]   = $tableAlias . '.' . $discrColumn;
65
66 42
        $resultColumnName = $this->platform->getSQLResultCasing($discrColumn);
67
68 42
        $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
69 42
        $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn, false, $discrColumnType);
70
71
        // Append subclass columns
72 42 View Code Duplication
        foreach ($this->class->subClasses as $subClassName) {
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...
73 27
            $subClass = $this->em->getClassMetadata($subClassName);
74
75
            // Regular columns
76 27
            foreach ($subClass->fieldMappings as $fieldName => $mapping) {
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
77 27
                if (isset($mapping['inherited'])) {
78 27
                    continue;
79
                }
80
81 15
                $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
0 ignored issues
show
Compatibility introduced by
$subClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
82
            }
83
84
            // Foreign key columns
85 27
            foreach ($subClass->associationMappings as $assoc) {
0 ignored issues
show
Bug introduced by
Accessing associationMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
86 24
                if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE) || isset($assoc['inherited'])) {
87 23
                    continue;
88
                }
89
90 3
                $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
91
92 3
                foreach ($assoc['joinColumns'] as $joinColumn) {
93 3
                    $columnList[] = $this->getSelectJoinColumnSQL(
94 3
                        $tableAlias,
95 3
                        $joinColumn['name'],
96 3
                        $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform),
0 ignored issues
show
Compatibility introduced by
$subClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
97 27
                        PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em)
0 ignored issues
show
Compatibility introduced by
$targetClass of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
98
                    );
99
                }
100
            }
101
        }
102
103 42
        $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
104
105 42
        return $this->currentPersisterContext->selectColumnListSql;
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111 176
    protected function getInsertColumnList()
112
    {
113 176
        $columns = parent::getInsertColumnList();
114
115
        // Add discriminator column to the INSERT SQL
116 176
        $columns[] = $this->class->discriminatorColumn['name'];
117
118 176
        return $columns;
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124 44
    protected function getSQLTableAlias($className, $assocName = '')
125
    {
126 44
        return parent::getSQLTableAlias($this->class->rootEntityName, $assocName);
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 42
    protected function getSelectConditionSQL(array $criteria, $assoc = null)
133
    {
134 42
        $conditionSql = parent::getSelectConditionSQL($criteria, $assoc);
135
136 42
        if ($conditionSql) {
137 37
            $conditionSql .= ' AND ';
138
        }
139
140 42
        return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146 4
    protected function getSelectConditionCriteriaSQL(Criteria $criteria)
147
    {
148 4
        $conditionSql = parent::getSelectConditionCriteriaSQL($criteria);
149
150 3
        if ($conditionSql) {
151 3
            $conditionSql .= ' AND ';
152
        }
153
154 3
        return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
155
    }
156
157
    /**
158
     * @return string
159
     */
160 44
    protected function getSelectConditionDiscriminatorValueSQL()
161
    {
162 44
        $values = [];
163
164 44
        if ($this->class->discriminatorValue !== null) { // discriminators can be 0
165 30
            $values[] = $this->conn->quote($this->class->discriminatorValue);
166
        }
167
168 44
        $discrValues = array_flip($this->class->discriminatorMap);
169
170 44
        foreach ($this->class->subClasses as $subclassName) {
171 28
            $values[] = $this->conn->quote($discrValues[$subclassName]);
172
        }
173
174 44
        $values     = implode(', ', $values);
175 44
        $discColumn = $this->class->discriminatorColumn['name'];
176 44
        $tableAlias = $this->getSQLTableAlias($this->class->name);
177
178 44
        return $tableAlias . '.' . $discColumn . ' IN (' . $values . ')';
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184 44
    protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
185
    {
186
        // Ensure that the filters are applied to the root entity of the inheritance tree
187 44
        $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName);
188
        // we don't care about the $targetTableAlias, in a STI there is only one table.
189
190 44
        return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias);
0 ignored issues
show
Compatibility introduced by
$targetEntity of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
191
    }
192
}
193