Failed Conditions
Push — develop ( 6355a9...c47956 )
by Guilherme
63:54
created

ClassMetadataExporter::exportProperties()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 2
1
<?php
2
3
/*
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the MIT license. For more information, see
18
 * <http://www.doctrine-project.org>.
19
 */
20
21
declare(strict_types=1);
22
23
namespace Doctrine\ORM\Mapping\Exporter;
24
25
use Doctrine\Common\Inflector\Inflector;
26
use Doctrine\ORM\Mapping;
27
28
class ClassMetadataExporter implements Exporter
29
{
30
    const VARIABLE = '$this';
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function export($value, int $indentationLevel = 0) : string
36
    {
37
        /** @var Mapping\ClassMetadata $value */
38
        $reflectionClass = $value->getReflectionClass();
39
        $namespace       = $reflectionClass->getNamespaceName();
40
        $lines           = [];
41
42
        $lines[] = '<?php';
43
        $lines[] = null;
44
45
        if ($namespace) {
46
            $lines[] = 'namespace ' . $namespace . ';';
47
            $lines[] = null;
48
        }
49
50
        $lines[] = 'use Doctrine\DBAL\Types\Type;';
51
        $lines[] = 'use Doctrine\ORM\Mapping;';
52
        $lines[] = 'use Doctrine\ORM\Mapping\Factory\ClassMetadataBuildingContext;';
53
        $lines[] = null;
54
        $lines[] = $this->exportClass($value, $indentationLevel);
55
        $lines[] = null;
56
57
        return implode(PHP_EOL, $lines);
58
    }
59
60
    /**
61
     * @param Mapping\ClassMetadata $metadata
62
     * @param int                   $indentationLevel
63
     *
64
     * @return string
65
     */
66
    private function exportClass(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
67
    {
68
        $reflectionClass   = $metadata->getReflectionClass();
69
        $shortClassName    = $reflectionClass->getShortName();
70
        $extendedClassName = ($metadata instanceof Mapping\MappedSuperClassMetadata)
71
            ? 'MappedSuperClassMetadata'
72
            : 'EntityClassMetadata'
73
        ;
74
75
        $lines[] = sprintf('class %sClassMetadata extends Mapping\%s', $shortClassName, $extendedClassName);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$lines was never initialized. Although not strictly required by PHP, it is generally a good practice to add $lines = 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...
76
        $lines[] = '{';
77
        $lines[] = $this->exportConstructor($metadata, $indentationLevel + 1);
78
        $lines[] = '}';
79
        $lines[] = null;
80
81
        return implode(PHP_EOL, $lines);
82
    }
83
84
    /**
85
     * @param Mapping\ClassMetadata $metadata
86
     * @param int                   $indentationLevel
87
     *
88
     * @return string
89
     */
90
    private function exportConstructor(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
91
    {
92
        $indentation     = str_repeat(self::INDENTATION, $indentationLevel);
93
        $bodyIndentation = str_repeat(self::INDENTATION, $indentationLevel + 1);
94
        $objectReference = $bodyIndentation . static::VARIABLE;
95
        $lines           = [];
96
97
        $lines[] = $indentation . 'public function __construct(';
98
        $lines[] = $bodyIndentation . 'ClassMetadataBuildingContext $metadataBuildingContext,';
99
        $lines[] = $bodyIndentation . '?ClassMetadata $parent = null';
100
        $lines[] = $indentation . ')';
101
        $lines[] = $indentation . '{';
102
        $lines[] = $bodyIndentation . 'parent::__construct("' . $metadata->getClassName() . '", $parent);';
103
104
        if ($metadata->getCustomRepositoryClassName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metadata->getCustomRepositoryClassName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
105
            $lines[] = null;
106
            $lines[] = $objectReference . '->setCustomRepositoryClassName("' . $metadata->getCustomRepositoryClassName() . '");';
107
        }
108
109 View Code Duplication
        if ($metadata->changeTrackingPolicy) {
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...
110
            $lines[] = null;
111
            $lines[] = $objectReference . '->setChangeTrackingPolicy(Mapping\ChangeTrackingPolicy::' . strtoupper($metadata->changeTrackingPolicy) . ');';
112
        }
113
114
        $lines[] = $this->exportInheritance($metadata, $indentationLevel);
115
        $lines[] = $this->exportTable($metadata, $indentationLevel);
116
        $lines[] = $this->exportProperties($metadata, $indentationLevel);
117
        $lines[] = $this->exportLifecycleCallbacks($metadata, $indentationLevel);
118
        $lines[] = $indentation . '}';
119
120
        return implode(PHP_EOL, $lines);
121
    }
122
123
    /**
124
     * @param Mapping\ClassMetadata $metadata
125
     * @param int                   $indentationLevel
126
     *
127
     * @return string
128
     */
129
    private function exportInheritance(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
130
    {
131
        $bodyIndentation = str_repeat(self::INDENTATION, $indentationLevel + 1);
132
        $objectReference = $bodyIndentation . static::VARIABLE;
133
        $lines           = [];
134
135 View Code Duplication
        if ($metadata->inheritanceType) {
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...
136
            $lines[] = null;
137
            $lines[] = $objectReference . '->setInheritanceType(Mapping\InheritanceType::' . strtoupper($metadata->inheritanceType) . ');';
138
        }
139
140 View Code Duplication
        if ($metadata->discriminatorColumn) {
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...
141
            $lines[] = null;
142
            $lines[] = $bodyIndentation . '// Discriminator mapping';
143
            $lines[] = $this->exportDiscriminatorMetadata($metadata, $indentationLevel + 1);
144
        }
145
146
        return implode(PHP_EOL, $lines);
147
    }
148
149
    /**
150
     * @param Mapping\ClassMetadata $metadata
151
     * @param int                   $indentationLevel
152
     *
153
     * @return string
154
     */
155
    private function exportTable(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
156
    {
157
        $bodyIndentation = str_repeat(self::INDENTATION, $indentationLevel + 1);
158
        $lines           = [];
159
160 View Code Duplication
        if ($metadata->table) {
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...
161
            $lines[] = null;
162
            $lines[] = $bodyIndentation . '// Table';
163
            $lines[] = $this->exportTableMetadata($metadata->table, $indentationLevel + 1);
164
        }
165
166
        return implode(PHP_EOL, $lines);
167
    }
168
169
    /**
170
     * @param Mapping\ClassMetadata $metadata
171
     * @param int                   $indentationLevel
172
     *
173
     * @return string
174
     */
175
    private function exportProperties(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
176
    {
177
        $bodyIndentation = str_repeat(self::INDENTATION, $indentationLevel + 1);
178
        $lines           = [];
179
180
        foreach ($metadata->getProperties() as $name => $property) {
181
            $lines[] = null;
182
            $lines[] = $bodyIndentation . '// Property: ' . $name;
183
            $lines[] = $this->exportProperty($property, $indentationLevel + 1);
184
        }
185
186
        return implode(PHP_EOL, $lines);
187
    }
188
189
    /**
190
     * @param Mapping\ClassMetadata $metadata
191
     * @param int                   $indentationLevel
192
     *
193
     * @return string
194
     */
195
    private function exportLifecycleCallbacks(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
196
    {
197
        $bodyIndentation = str_repeat(self::INDENTATION, $indentationLevel + 1);
198
        $objectReference = $bodyIndentation . static::VARIABLE;
199
        $lines           = [];
200
201
        if ($metadata->lifecycleCallbacks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metadata->lifecycleCallbacks of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
202
            $lines[] = null;
203
            $lines[] = $bodyIndentation . '// Lifecycle callbacks';
204
205 View Code Duplication
            foreach ($metadata->lifecycleCallbacks as $event => $callbacks) {
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...
206
                foreach ($callbacks as $callback) {
207
                    $lines[] = $objectReference . '->addLifecycleCallback("' . $callback . '", "' . $event . '");';
208
                }
209
            }
210
        }
211
212
        return implode(PHP_EOL, $lines);
213
    }
214
215
    /**
216
     * @param Mapping\ClassMetadata $metadata
217
     * @param int                   $indentationLevel
218
     *
219
     * @return string
220
     */
221
    private function exportDiscriminatorMetadata(Mapping\ClassMetadata $metadata, int $indentationLevel) : string
222
    {
223
        $variableExporter      = new VariableExporter();
224
        $discriminatorExporter = new DiscriminatorColumnMetadataExporter();
225
        $indentation           = str_repeat(self::INDENTATION, $indentationLevel);
226
        $objectReference       = $indentation . static::VARIABLE;
227
        $lines                 = [];
228
229
        $lines[] = $discriminatorExporter->export($metadata->discriminatorColumn, $indentationLevel);
230
        $lines[] = null;
231
        $lines[] = $objectReference . '->setDiscriminatorColumn(' . $discriminatorExporter::VARIABLE . ');';
232
233
        if ($metadata->discriminatorMap) {
234
            $discriminatorMap = $variableExporter->export($metadata->discriminatorMap, $indentationLevel + 1);
235
236
            $lines[] = $objectReference . '->setDiscriminatorMap(' . $discriminatorMap . ');';
237
        }
238
239
        return implode(PHP_EOL, $lines);
240
    }
241
242
    /**
243
     * @param Mapping\TableMetadata $table
244
     * @param int                   $indentationLevel
245
     *
246
     * @return string
247
     */
248
    private function exportTableMetadata(Mapping\TableMetadata $table, int $indentationLevel) : string
249
    {
250
        $tableExporter   = new TableMetadataExporter();
251
        $indentation     = str_repeat(self::INDENTATION, $indentationLevel);
252
        $objectReference = $indentation . static::VARIABLE;
253
        $lines           = [];
254
255
        $lines[] = $tableExporter->export($table, $indentationLevel);
256
        $lines[] = null;
257
        $lines[] = $objectReference . '->setTable(' . $tableExporter::VARIABLE . ');';
258
259
        return implode(PHP_EOL, $lines);
260
    }
261
262
    /**
263
     * @param Mapping\Property $property
264
     * @param int              $indentationLevel
265
     *
266
     * @return string
267
     */
268
    private function exportProperty(Mapping\Property $property, int $indentationLevel) : string
269
    {
270
        $indentation     = str_repeat(self::INDENTATION, $indentationLevel);
271
        $objectReference = $indentation . static::VARIABLE;
272
        $lines           = [];
273
274
        switch (true) {
275
            case ($property instanceof Mapping\VersionFieldMetadata):
276
                $propertyExporter = new VersionFieldMetadataExporter();
277
                break;
278
279
            case ($property instanceof Mapping\FieldMetadata):
280
                $propertyExporter = new FieldMetadataExporter();
281
                break;
282
283
            case ($property instanceof Mapping\OneToOneAssociationMetadata):
284
                $propertyExporter = new OneToOneAssociationMetadataExporter();
285
                break;
286
287
            case ($property instanceof Mapping\OneToManyAssociationMetadata):
288
                $propertyExporter = new OneToManyAssociationMetadataExporter();
289
                break;
290
291
            case ($property instanceof Mapping\ManyToOneAssociationMetadata):
292
                $propertyExporter = new ManyToOneAssociationMetadataExporter();
293
                break;
294
295
            case ($property instanceof Mapping\ManyToManyAssociationMetadata):
296
                $propertyExporter = new ManyToManyAssociationMetadataExporter();
297
                break;
298
299
            default:
300
                $propertyExporter = new TransientMetadataExporter();
301
                break;
302
        }
303
304
        $lines[] = $propertyExporter->export($property, $indentationLevel);
305
        $lines[] = null;
306
        $lines[] = $objectReference . '->addProperty(' . $propertyExporter::VARIABLE . ');';
307
308
        return implode(PHP_EOL, $lines);
309
    }
310
}
311