Passed
Pull Request — master (#30)
by David
05:42 queued 02:14
created

ScalarBeanPropertyDescriptor::getAnnotations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 0
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace TheCodingMachine\TDBM\Utils;
4
5
use Doctrine\DBAL\Schema\Column;
6
use Doctrine\DBAL\Schema\Table;
7
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
8
use Ramsey\Uuid\Uuid;
9
use TheCodingMachine\TDBM\TDBMException;
10
use TheCodingMachine\TDBM\Utils\Annotation\Annotation;
11
use TheCodingMachine\TDBM\Utils\Annotation\AnnotationParser;
12
use TheCodingMachine\TDBM\Utils\Annotation\Annotations;
13
14
/**
15
 * This class represent a property in a bean (a property has a getter, a setter, etc...).
16
 */
17
class ScalarBeanPropertyDescriptor extends AbstractBeanPropertyDescriptor
18
{
19
    /**
20
     * @var Column
21
     */
22
    private $column;
23
24
    /**
25
     * @var Annotations
26
     */
27
    private $annotations;
28
29
    /**
30
     * ScalarBeanPropertyDescriptor constructor.
31
     * @param Table $table
32
     * @param Column $column
33
     * @param NamingStrategyInterface $namingStrategy
34
     */
35
    public function __construct(Table $table, Column $column, NamingStrategyInterface $namingStrategy)
36
    {
37
        parent::__construct($table, $namingStrategy);
38
        $this->table = $table;
39
        $this->column = $column;
40
    }
41
42
    /**
43
     * Returns the foreign-key the column is part of, if any. null otherwise.
44
     *
45
     * @return ForeignKeyConstraint|null
46
     */
47
    public function getForeignKey()
48
    {
49
        return false;
50
    }
51
52
    /**
53
     * Returns the param annotation for this property (useful for constructor).
54
     *
55
     * @return string
56
     */
57
    public function getParamAnnotation()
58
    {
59
        $paramType = $this->getPhpType();
60
61
        $str = '     * @param %s %s';
62
63
        return sprintf($str, $paramType, $this->getVariableName());
64
    }
65
66
    /**
67
     * Returns the name of the class linked to this property or null if this is not a foreign key.
68
     *
69
     * @return null|string
70
     */
71
    public function getClassName(): ?string
72
    {
73
        return null;
74
    }
75
76
    /**
77
     * Returns the PHP type for the property (it can be a scalar like int, bool, or class names, like \DateTimeInterface, App\Bean\User....)
78
     *
79
     * @return string
80
     */
81
    public function getPhpType(): string
82
    {
83
        $type = $this->column->getType();
84
        return TDBMDaoGenerator::dbalTypeToPhpType($type);
85
    }
86
87
    /**
88
     * Returns true if the property is compulsory (and therefore should be fetched in the constructor).
89
     *
90
     * @return bool
91
     */
92
    public function isCompulsory()
93
    {
94
        return $this->column->getNotnull() && !$this->isAutoincrement() && $this->column->getDefault() === null && !$this->hasUuidAnnotation();
95
    }
96
97
    private function isAutoincrement() : bool
98
    {
99
        return $this->column->getAutoincrement() || $this->getAutoincrementAnnotation() !== null;
100
    }
101
102
    private function hasUuidAnnotation(): bool
103
    {
104
        return $this->getUuidAnnotation() !== null;
105
    }
106
107
    private function getUuidAnnotation(): ?Annotation
108
    {
109
        return $this->getAnnotations()->findAnnotation('UUID');
110
    }
111
112
    private function getAutoincrementAnnotation(): ?Annotation
113
    {
114
        return $this->getAnnotations()->findAnnotation('Autoincrement');
115
    }
116
117
    private function getAnnotations(): Annotations
118
    {
119
        if ($this->annotations === null) {
120
            $comment = $this->column->getComment();
121
            if ($comment === null) {
122
                return new Annotations([]);
123
            }
124
            $parser = new AnnotationParser();
125
            $this->annotations = $parser->parse($comment);
126
        }
127
        return $this->annotations;
128
    }
129
130
    /**
131
     * Returns true if the property has a default value (or if the @UUID annotation is set for the column)
132
     *
133
     * @return bool
134
     */
135
    public function hasDefault()
136
    {
137
        return $this->column->getDefault() !== null || $this->hasUuidAnnotation();
138
    }
139
140
    /**
141
     * Returns the code that assigns a value to its default value.
142
     *
143
     * @return string
144
     */
145
    public function assignToDefaultCode()
146
    {
147
        $str = '        $this->%s(%s);';
148
149
        $uuidAnnotation = $this->getUuidAnnotation();
150
        if ($uuidAnnotation !== null) {
151
            $comment = trim($uuidAnnotation->getAnnotationComment(), '\'"');
152
            switch ($comment) {
153
                case '':
154
                case 'v1':
155
                    $defaultCode = '(string) Uuid::uuid1()';
156
                    break;
157
                case 'v4':
158
                    $defaultCode = '(string) Uuid::uuid4()';
159
                    break;
160
                default:
161
                    throw new TDBMException('@UUID annotation accepts either "v1" or "v4" parameter. Unexpected parameter: '.$comment);
162
            }
163
        } else {
164
            $default = $this->column->getDefault();
165
166
            if (in_array(strtoupper($default), ['CURRENT_TIMESTAMP' /* MySQL */, 'NOW()' /* PostgreSQL */, 'SYSDATE' /* Oracle */ ], true)) {
167
                $defaultCode = 'new \DateTimeImmutable()';
168
            } else {
169
                $defaultCode = var_export($this->column->getDefault(), true);
170
            }
171
        }
172
173
        return sprintf($str, $this->getSetterName(), $defaultCode);
174
    }
175
176
    /**
177
     * Returns true if the property is the primary key.
178
     *
179
     * @return bool
180
     */
181
    public function isPrimaryKey()
182
    {
183
        return in_array($this->column->getName(), $this->table->getPrimaryKey()->getUnquotedColumns());
184
    }
185
186
    /**
187
     * Returns the PHP code for getters and setters.
188
     *
189
     * @return string
190
     */
191
    public function getGetterSetterCode()
192
    {
193
        $normalizedType = $this->getPhpType();
194
195
        $columnGetterName = $this->getGetterName();
196
        $columnSetterName = $this->getSetterName();
197
198
        // A column type can be forced if it is not nullable and not auto-incrementable (for auto-increment columns, we can get "null" as long as the bean is not saved).
199
        $isNullable = !$this->column->getNotnull() || $this->isAutoincrement();
200
201
        $getterAndSetterCode = '    /**
202
     * The getter for the "%s" column.
203
     *
204
     * @return %s
205
     */
206
    public function %s() : %s%s
207
    {
208
        return $this->get(%s, %s);
209
    }
210
211
    /**
212
     * The setter for the "%s" column.
213
     *
214
     * @param %s $%s
215
     */
216
    public function %s(%s%s $%s) : void
217
    {
218
        $this->set(%s, $%s, %s);
219
    }
220
221
';
222
223
        return sprintf($getterAndSetterCode,
224
            // Getter
225
            $this->column->getName(),
226
            $normalizedType.($isNullable ? '|null' : ''),
227
            $columnGetterName,
228
            ($isNullable ? '?' : ''),
229
            $normalizedType,
230
            var_export($this->column->getName(), true),
231
            var_export($this->table->getName(), true),
232
            // Setter
233
            $this->column->getName(),
234
            $normalizedType.($isNullable ? '|null' : ''),
235
            $this->column->getName(),
236
            $columnSetterName,
237
            $this->column->getNotnull() ? '' : '?',
238
            $normalizedType,
239
                //$castTo,
240
            $this->column->getName(),
241
            var_export($this->column->getName(), true),
242
            $this->column->getName(),
243
            var_export($this->table->getName(), true)
244
        );
245
    }
246
247
    /**
248
     * Returns the part of code useful when doing json serialization.
249
     *
250
     * @return string
251
     */
252
    public function getJsonSerializeCode()
253
    {
254
        $normalizedType = $this->getPhpType();
255
256
        if ($normalizedType == '\\DateTimeImmutable') {
257
            return '        $array['.var_export($this->namingStrategy->getJsonProperty($this), true).'] = ($this->'.$this->getGetterName().'() === null) ? null : $this->'.$this->getGetterName()."()->format('c');\n";
258
        } else {
259
            return '        $array['.var_export($this->namingStrategy->getJsonProperty($this), true).'] = $this->'.$this->getGetterName()."();\n";
260
        }
261
    }
262
263
    /**
264
     * Returns the column name.
265
     *
266
     * @return string
267
     */
268
    public function getColumnName()
269
    {
270
        return $this->column->getName();
271
    }
272
}
273