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
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* This class represent a property in a bean (a property has a getter, a setter, etc...). |
15
|
|
|
*/ |
16
|
|
|
class ScalarBeanPropertyDescriptor extends AbstractBeanPropertyDescriptor |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* @var Column |
20
|
|
|
*/ |
21
|
|
|
private $column; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* ScalarBeanPropertyDescriptor constructor. |
25
|
|
|
* @param Table $table |
26
|
|
|
* @param Column $column |
27
|
|
|
* @param NamingStrategyInterface $namingStrategy |
28
|
|
|
*/ |
29
|
|
|
public function __construct(Table $table, Column $column, NamingStrategyInterface $namingStrategy) |
30
|
|
|
{ |
31
|
|
|
parent::__construct($table, $namingStrategy); |
32
|
|
|
$this->table = $table; |
33
|
|
|
$this->column = $column; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Returns the foreign-key the column is part of, if any. null otherwise. |
38
|
|
|
* |
39
|
|
|
* @return ForeignKeyConstraint|null |
40
|
|
|
*/ |
41
|
|
|
public function getForeignKey() |
42
|
|
|
{ |
43
|
|
|
return false; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Returns the param annotation for this property (useful for constructor). |
48
|
|
|
* |
49
|
|
|
* @return string |
50
|
|
|
*/ |
51
|
|
|
public function getParamAnnotation() |
52
|
|
|
{ |
53
|
|
|
$paramType = $this->getPhpType(); |
54
|
|
|
|
55
|
|
|
$str = ' * @param %s %s'; |
56
|
|
|
|
57
|
|
|
return sprintf($str, $paramType, $this->getVariableName()); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Returns the name of the class linked to this property or null if this is not a foreign key. |
62
|
|
|
* |
63
|
|
|
* @return null|string |
64
|
|
|
*/ |
65
|
|
|
public function getClassName(): ?string |
66
|
|
|
{ |
67
|
|
|
return null; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Returns the PHP type for the property (it can be a scalar like int, bool, or class names, like \DateTimeInterface, App\Bean\User....) |
72
|
|
|
* |
73
|
|
|
* @return string |
74
|
|
|
*/ |
75
|
|
|
public function getPhpType(): string |
76
|
|
|
{ |
77
|
|
|
$type = $this->column->getType(); |
78
|
|
|
return TDBMDaoGenerator::dbalTypeToPhpType($type); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Returns true if the property is compulsory (and therefore should be fetched in the constructor). |
83
|
|
|
* |
84
|
|
|
* @return bool |
85
|
|
|
*/ |
86
|
|
|
public function isCompulsory() |
87
|
|
|
{ |
88
|
|
|
return $this->column->getNotnull() && !$this->column->getAutoincrement() && $this->column->getDefault() === null && !$this->hasUuidAnnotation(); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
private function hasUuidAnnotation(): bool |
92
|
|
|
{ |
93
|
|
|
return $this->getUuidAnnotation() !== null; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
private function getUuidAnnotation(): ?Annotation |
97
|
|
|
{ |
98
|
|
|
$comment = $this->column->getComment(); |
99
|
|
|
if ($comment === null) { |
100
|
|
|
return null; |
101
|
|
|
} |
102
|
|
|
$parser = new AnnotationParser(); |
103
|
|
|
$annotations = $parser->parse($comment); |
104
|
|
|
return $annotations->findAnnotation('UUID'); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Returns true if the property has a default value (or if the @UUID annotation is set for the column) |
109
|
|
|
* |
110
|
|
|
* @return bool |
111
|
|
|
*/ |
112
|
|
|
public function hasDefault() |
113
|
|
|
{ |
114
|
|
|
return $this->column->getDefault() !== null || $this->hasUuidAnnotation(); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Returns the code that assigns a value to its default value. |
119
|
|
|
* |
120
|
|
|
* @return string |
121
|
|
|
*/ |
122
|
|
|
public function assignToDefaultCode() |
123
|
|
|
{ |
124
|
|
|
$str = ' $this->%s(%s);'; |
125
|
|
|
|
126
|
|
|
$uuidAnnotation = $this->getUuidAnnotation(); |
127
|
|
|
if ($uuidAnnotation !== null) { |
128
|
|
|
$comment = trim($uuidAnnotation->getAnnotationComment(), '\'"'); |
129
|
|
|
switch ($comment) { |
130
|
|
|
case '': |
|
|
|
|
131
|
|
|
case 'v1': |
132
|
|
|
$defaultCode = 'Uuid::uuid1()'; |
133
|
|
|
break; |
134
|
|
|
case 'v4': |
135
|
|
|
$defaultCode = 'Uuid::uuid4()'; |
136
|
|
|
break; |
137
|
|
|
default: |
138
|
|
|
throw new TDBMException('@UUID annotation accepts either "v1" or "v4" parameter. Unexpected parameter: '.$comment); |
139
|
|
|
} |
140
|
|
|
} else { |
141
|
|
|
$default = $this->column->getDefault(); |
142
|
|
|
|
143
|
|
|
if (strtoupper($default) === 'CURRENT_TIMESTAMP') { |
144
|
|
|
$defaultCode = 'new \DateTimeImmutable()'; |
145
|
|
|
} else { |
146
|
|
|
$defaultCode = var_export($this->column->getDefault(), true); |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
return sprintf($str, $this->getSetterName(), $defaultCode); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Returns true if the property is the primary key. |
155
|
|
|
* |
156
|
|
|
* @return bool |
157
|
|
|
*/ |
158
|
|
|
public function isPrimaryKey() |
159
|
|
|
{ |
160
|
|
|
return in_array($this->column->getName(), $this->table->getPrimaryKeyColumns()); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Returns the PHP code for getters and setters. |
165
|
|
|
* |
166
|
|
|
* @return string |
167
|
|
|
*/ |
168
|
|
|
public function getGetterSetterCode() |
169
|
|
|
{ |
170
|
|
|
$normalizedType = $this->getPhpType(); |
171
|
|
|
|
172
|
|
|
$columnGetterName = $this->getGetterName(); |
173
|
|
|
$columnSetterName = $this->getSetterName(); |
174
|
|
|
|
175
|
|
|
// 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). |
176
|
|
|
$isNullable = !$this->column->getNotnull() || $this->column->getAutoincrement(); |
177
|
|
|
|
178
|
|
|
$getterAndSetterCode = ' /** |
179
|
|
|
* The getter for the "%s" column. |
180
|
|
|
* |
181
|
|
|
* @return %s |
182
|
|
|
*/ |
183
|
|
|
public function %s() : %s%s |
184
|
|
|
{ |
185
|
|
|
return $this->get(%s, %s); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* The setter for the "%s" column. |
190
|
|
|
* |
191
|
|
|
* @param %s $%s |
192
|
|
|
*/ |
193
|
|
|
public function %s(%s%s $%s) : void |
194
|
|
|
{ |
195
|
|
|
$this->set(%s, $%s, %s); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
'; |
199
|
|
|
|
200
|
|
|
return sprintf($getterAndSetterCode, |
201
|
|
|
// Getter |
202
|
|
|
$this->column->getName(), |
203
|
|
|
$normalizedType.($isNullable ? '|null' : ''), |
204
|
|
|
$columnGetterName, |
205
|
|
|
($isNullable ? '?' : ''), |
206
|
|
|
$normalizedType, |
207
|
|
|
var_export($this->column->getName(), true), |
208
|
|
|
var_export($this->table->getName(), true), |
209
|
|
|
// Setter |
210
|
|
|
$this->column->getName(), |
211
|
|
|
$normalizedType, |
212
|
|
|
$this->column->getName(), |
213
|
|
|
$columnSetterName, |
214
|
|
|
$this->column->getNotnull() ? '' : '?', |
215
|
|
|
$normalizedType, |
216
|
|
|
//$castTo, |
217
|
|
|
$this->column->getName(), |
218
|
|
|
var_export($this->column->getName(), true), |
219
|
|
|
$this->column->getName(), |
220
|
|
|
var_export($this->table->getName(), true) |
221
|
|
|
); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Returns the part of code useful when doing json serialization. |
226
|
|
|
* |
227
|
|
|
* @return string |
228
|
|
|
*/ |
229
|
|
|
public function getJsonSerializeCode() |
230
|
|
|
{ |
231
|
|
|
$normalizedType = $this->getPhpType(); |
232
|
|
|
|
233
|
|
|
if ($normalizedType == '\\DateTimeInterface') { |
234
|
|
|
return ' $array['.var_export($this->namingStrategy->getJsonProperty($this), true).'] = ($this->'.$this->getGetterName().'() === null) ? null : $this->'.$this->getGetterName()."()->format('c');\n"; |
235
|
|
|
} else { |
236
|
|
|
return ' $array['.var_export($this->namingStrategy->getJsonProperty($this), true).'] = $this->'.$this->getGetterName()."();\n"; |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Returns the column name. |
242
|
|
|
* |
243
|
|
|
* @return string |
244
|
|
|
*/ |
245
|
|
|
public function getColumnName() |
246
|
|
|
{ |
247
|
|
|
return $this->column->getName(); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break
.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.