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\Tools; |
21
|
|
|
|
22
|
|
|
use Doctrine\Common\Inflector\Inflector; |
23
|
|
|
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo; |
24
|
|
|
use Doctrine\ODM\MongoDB\Types\Type; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Generic class used to generate PHP5 document classes from ClassMetadataInfo instances |
28
|
|
|
* |
29
|
|
|
* [php] |
30
|
|
|
* $classes = $dm->getClassMetadataInfoFactory()->getAllMetadata(); |
31
|
|
|
* |
32
|
|
|
* $generator = new \Doctrine\ODM\MongoDB\Tools\DocumentGenerator(); |
33
|
|
|
* $generator->setGenerateAnnotations(true); |
34
|
|
|
* $generator->setGenerateStubMethods(true); |
35
|
|
|
* $generator->setRegenerateDocumentIfExists(false); |
36
|
|
|
* $generator->setUpdateDocumentIfExists(true); |
37
|
|
|
* $generator->generate($classes, '/path/to/generate/documents'); |
38
|
|
|
* |
39
|
|
|
* @since 1.0 |
40
|
|
|
* @author Benjamin Eberlei <[email protected]> |
41
|
|
|
* @author Guilherme Blanco <[email protected]> |
42
|
|
|
* @author Jonathan Wage <[email protected]> |
43
|
|
|
* @author Roman Borschel <[email protected]> |
44
|
|
|
*/ |
45
|
|
|
class DocumentGenerator |
46
|
|
|
{ |
47
|
|
|
/** |
48
|
|
|
* @var bool |
49
|
|
|
*/ |
50
|
|
|
private $backupExisting = true; |
51
|
|
|
|
52
|
|
|
/** The extension to use for written php files */ |
53
|
|
|
private $extension = '.php'; |
54
|
|
|
|
55
|
|
|
/** Whether or not the current ClassMetadataInfo instance is new or old */ |
56
|
|
|
private $isNew = true; |
57
|
|
|
|
58
|
|
|
private $staticReflection = array(); |
59
|
|
|
|
60
|
|
|
/** Number of spaces to use for indention in generated code */ |
61
|
|
|
private $numSpaces = 4; |
62
|
|
|
|
63
|
|
|
/** The actual spaces to use for indention */ |
64
|
|
|
private $spaces = ' '; |
65
|
|
|
|
66
|
|
|
/** The class all generated documents should extend */ |
67
|
|
|
private $classToExtend; |
68
|
|
|
|
69
|
|
|
/** Whether or not to generate annotations */ |
70
|
|
|
private $generateAnnotations = false; |
71
|
|
|
|
72
|
|
|
/** Whether or not to generate stub methods */ |
73
|
|
|
private $generateDocumentStubMethods = false; |
74
|
|
|
|
75
|
|
|
/** Whether or not to update the document class if it exists already */ |
76
|
|
|
private $updateDocumentIfExists = false; |
77
|
|
|
|
78
|
|
|
/** Whether or not to re-generate document class if it exists already */ |
79
|
|
|
private $regenerateDocumentIfExists = false; |
80
|
|
|
|
81
|
|
|
private static $classTemplate = |
82
|
|
|
'<?php |
83
|
|
|
|
84
|
|
|
<namespace> |
85
|
|
|
|
86
|
|
|
<imports> |
87
|
|
|
|
88
|
|
|
<documentAnnotation> |
89
|
|
|
<documentClassName> |
90
|
|
|
{ |
91
|
|
|
<documentBody> |
92
|
|
|
}'; |
93
|
|
|
|
94
|
|
|
private static $getMethodTemplate = |
95
|
|
|
'/** |
96
|
|
|
* <description> |
97
|
|
|
* |
98
|
|
|
* @return <variableType>$<variableName> |
99
|
|
|
*/ |
100
|
|
|
public function <methodName>() |
101
|
|
|
{ |
102
|
|
|
<spaces>return $this-><fieldName>; |
103
|
|
|
}'; |
104
|
|
|
|
105
|
|
|
private static $setMethodTemplate = |
106
|
|
|
'/** |
107
|
|
|
* <description> |
108
|
|
|
* |
109
|
|
|
* @param <variableType>$<variableName> |
110
|
|
|
* @return self |
111
|
|
|
*/ |
112
|
|
|
public function <methodName>(<methodTypeHint>$<variableName><variableDefault>) |
113
|
|
|
{ |
114
|
|
|
<spaces>$this-><fieldName> = $<variableName>; |
115
|
|
|
<spaces>return $this; |
116
|
|
|
}'; |
117
|
|
|
|
118
|
|
|
private static $addMethodTemplate = |
119
|
|
|
'/** |
120
|
|
|
* <description> |
121
|
|
|
* |
122
|
|
|
* @param <variableType>$<variableName> |
123
|
|
|
*/ |
124
|
|
|
public function <methodName>(<methodTypeHint>$<variableName>) |
125
|
|
|
{ |
126
|
|
|
<spaces>$this-><fieldName>[] = $<variableName>; |
127
|
|
|
}'; |
128
|
|
|
|
129
|
|
|
private static $removeMethodTemplate = |
130
|
|
|
'/** |
131
|
|
|
* <description> |
132
|
|
|
* |
133
|
|
|
* @param <variableType>$<variableName> |
134
|
|
|
*/ |
135
|
|
|
public function <methodName>(<methodTypeHint>$<variableName>) |
136
|
|
|
{ |
137
|
|
|
<spaces>$this-><fieldName>->removeElement($<variableName>); |
138
|
|
|
}'; |
139
|
|
|
|
140
|
|
|
private static $lifecycleCallbackMethodTemplate = |
141
|
|
|
'<comment> |
142
|
|
|
public function <methodName>() |
143
|
|
|
{ |
144
|
|
|
<spaces>// Add your code here |
145
|
|
|
}'; |
146
|
|
|
|
147
|
|
|
private static $constructorMethodTemplate = |
148
|
|
|
'public function __construct() |
149
|
|
|
{ |
150
|
|
|
<collections> |
151
|
|
|
} |
152
|
|
|
'; |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Generate and write document classes for the given array of ClassMetadataInfo instances |
156
|
|
|
* |
157
|
|
|
* @param array $metadatas |
158
|
|
|
* @param string $outputDirectory |
159
|
|
|
* @return void |
160
|
|
|
*/ |
161
|
|
|
public function generate(array $metadatas, $outputDirectory) |
162
|
|
|
{ |
163
|
|
|
foreach ($metadatas as $metadata) { |
164
|
|
|
$this->writeDocumentClass($metadata, $outputDirectory); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Generated and write document class to disk for the given ClassMetadataInfo instance |
170
|
|
|
* |
171
|
|
|
* @param ClassMetadataInfo $metadata |
172
|
|
|
* @param string $outputDirectory |
173
|
|
|
* @throws \RuntimeException |
174
|
|
|
* @return void |
175
|
|
|
*/ |
176
|
9 |
|
public function writeDocumentClass(ClassMetadataInfo $metadata, $outputDirectory) |
177
|
|
|
{ |
178
|
9 |
|
$path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension; |
179
|
9 |
|
$dir = dirname($path); |
180
|
|
|
|
181
|
9 |
|
if ( ! is_dir($dir)) { |
182
|
|
|
mkdir($dir, 0775, true); |
183
|
|
|
} |
184
|
|
|
|
185
|
9 |
|
$this->isNew = ! file_exists($path) || (file_exists($path) && $this->regenerateDocumentIfExists); |
186
|
|
|
|
187
|
9 |
|
if ( ! $this->isNew) { |
188
|
2 |
|
$this->parseTokensInDocumentFile($path); |
189
|
2 |
|
} |
190
|
|
|
|
191
|
9 |
|
if ($this->backupExisting && file_exists($path)) { |
192
|
2 |
|
$backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . '~'; |
193
|
2 |
|
if ( ! copy($path, $backupPath)) { |
194
|
|
|
throw new \RuntimeException("Attempt to backup overwritten document file but copy operation failed."); |
195
|
|
|
} |
196
|
2 |
|
} |
197
|
|
|
|
198
|
|
|
// If document doesn't exist or we're re-generating the documents entirely |
199
|
9 |
|
if ($this->isNew) { |
200
|
8 |
|
file_put_contents($path, $this->generateDocumentClass($metadata)); |
201
|
|
|
|
202
|
|
|
// If document exists and we're allowed to update the document class |
203
|
9 |
|
} elseif ( ! $this->isNew && $this->updateDocumentIfExists) { |
204
|
2 |
|
file_put_contents($path, $this->generateUpdatedDocumentClass($metadata, $path)); |
205
|
2 |
|
} |
206
|
9 |
|
chmod($path, 0664); |
207
|
9 |
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Generate a PHP5 Doctrine 2 document class from the given ClassMetadataInfo instance |
211
|
|
|
* |
212
|
|
|
* @param ClassMetadataInfo $metadata |
213
|
|
|
* @return string $code |
214
|
|
|
*/ |
215
|
8 |
|
public function generateDocumentClass(ClassMetadataInfo $metadata) |
216
|
|
|
{ |
217
|
|
|
$placeHolders = array( |
218
|
8 |
|
'<namespace>', |
219
|
8 |
|
'<imports>', |
220
|
8 |
|
'<documentAnnotation>', |
221
|
8 |
|
'<documentClassName>', |
222
|
|
|
'<documentBody>' |
223
|
8 |
|
); |
224
|
|
|
|
225
|
|
|
$replacements = array( |
226
|
8 |
|
$this->generateDocumentNamespace($metadata), |
227
|
8 |
|
$this->generateDocumentImports($metadata), |
|
|
|
|
228
|
8 |
|
$this->generateDocumentDocBlock($metadata), |
229
|
8 |
|
$this->generateDocumentClassName($metadata), |
230
|
8 |
|
$this->generateDocumentBody($metadata) |
231
|
8 |
|
); |
232
|
|
|
|
233
|
8 |
|
$code = str_replace($placeHolders, $replacements, self::$classTemplate); |
234
|
8 |
|
return str_replace('<spaces>', $this->spaces, $code); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Generate the updated code for the given ClassMetadataInfo and document at path |
239
|
|
|
* |
240
|
|
|
* @param ClassMetadataInfo $metadata |
241
|
|
|
* @param string $path |
242
|
|
|
* @return string $code; |
243
|
|
|
*/ |
244
|
2 |
|
public function generateUpdatedDocumentClass(ClassMetadataInfo $metadata, $path) |
245
|
|
|
{ |
246
|
2 |
|
$currentCode = file_get_contents($path); |
247
|
|
|
|
248
|
2 |
|
$body = $this->generateDocumentBody($metadata); |
249
|
2 |
|
$body = str_replace('<spaces>', $this->spaces, $body); |
250
|
2 |
|
$last = strrpos($currentCode, '}'); |
251
|
|
|
|
252
|
2 |
|
return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : '') . "}\n"; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Set the number of spaces the exported class should have |
257
|
|
|
* |
258
|
|
|
* @param integer $numSpaces |
259
|
|
|
* @return void |
260
|
|
|
*/ |
261
|
|
|
public function setNumSpaces($numSpaces) |
262
|
|
|
{ |
263
|
|
|
$this->spaces = str_repeat(' ', $numSpaces); |
264
|
|
|
$this->numSpaces = $numSpaces; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Set the extension to use when writing php files to disk |
269
|
|
|
* |
270
|
|
|
* @param string $extension |
271
|
|
|
* @return void |
272
|
|
|
*/ |
273
|
|
|
public function setExtension($extension) |
274
|
|
|
{ |
275
|
|
|
$this->extension = $extension; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* Set the name of the class the generated classes should extend from |
280
|
|
|
* |
281
|
|
|
* @return void |
282
|
|
|
*/ |
283
|
1 |
|
public function setClassToExtend($classToExtend) |
284
|
|
|
{ |
285
|
1 |
|
$this->classToExtend = $classToExtend; |
286
|
1 |
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* Set whether or not to generate annotations for the document |
290
|
|
|
* |
291
|
|
|
* @param bool $bool |
292
|
|
|
* @return void |
293
|
|
|
*/ |
294
|
9 |
|
public function setGenerateAnnotations($bool) |
295
|
|
|
{ |
296
|
9 |
|
$this->generateAnnotations = $bool; |
297
|
9 |
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* Set whether or not to try and update the document if it already exists |
301
|
|
|
* |
302
|
|
|
* @param bool $bool |
303
|
|
|
* @return void |
304
|
|
|
*/ |
305
|
9 |
|
public function setUpdateDocumentIfExists($bool) |
306
|
|
|
{ |
307
|
9 |
|
$this->updateDocumentIfExists = $bool; |
308
|
9 |
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* Set whether or not to regenerate the document if it exists |
312
|
|
|
* |
313
|
|
|
* @param bool $bool |
314
|
|
|
* @return void |
315
|
|
|
*/ |
316
|
9 |
|
public function setRegenerateDocumentIfExists($bool) |
317
|
|
|
{ |
318
|
9 |
|
$this->regenerateDocumentIfExists = $bool; |
319
|
9 |
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* Set whether or not to generate stub methods for the document |
323
|
|
|
* |
324
|
|
|
* @param bool $bool |
325
|
|
|
* @return void |
326
|
|
|
*/ |
327
|
9 |
|
public function setGenerateStubMethods($bool) |
328
|
|
|
{ |
329
|
9 |
|
$this->generateDocumentStubMethods = $bool; |
330
|
9 |
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* Should an existing document be backed up if it already exists? |
334
|
|
|
*/ |
335
|
|
|
public function setBackupExisting($bool) |
336
|
|
|
{ |
337
|
|
|
$this->backupExisting = $bool; |
338
|
|
|
} |
339
|
|
|
|
340
|
8 |
|
private function generateDocumentNamespace(ClassMetadataInfo $metadata) |
341
|
|
|
{ |
342
|
8 |
|
if ($this->hasNamespace($metadata)) { |
343
|
8 |
|
return 'namespace ' . $this->getNamespace($metadata) . ';'; |
344
|
|
|
} |
345
|
|
|
} |
346
|
|
|
|
347
|
8 |
|
private function generateDocumentClassName(ClassMetadataInfo $metadata) |
348
|
|
|
{ |
349
|
8 |
|
return 'class ' . $this->getClassName($metadata) . |
350
|
8 |
|
($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null); |
351
|
|
|
} |
352
|
|
|
|
353
|
9 |
|
private function generateDocumentBody(ClassMetadataInfo $metadata) |
354
|
|
|
{ |
355
|
9 |
|
$fieldMappingProperties = $this->generateDocumentFieldMappingProperties($metadata); |
356
|
9 |
|
$associationMappingProperties = $this->generateDocumentAssociationMappingProperties($metadata); |
357
|
9 |
|
$stubMethods = $this->generateDocumentStubMethods ? $this->generateDocumentStubMethods($metadata) : null; |
358
|
9 |
|
$lifecycleCallbackMethods = $this->generateDocumentLifecycleCallbackMethods($metadata); |
359
|
|
|
|
360
|
9 |
|
$code = array(); |
361
|
|
|
|
362
|
9 |
|
if ($fieldMappingProperties) { |
363
|
7 |
|
$code[] = $fieldMappingProperties; |
364
|
7 |
|
} |
365
|
|
|
|
366
|
9 |
|
if ($associationMappingProperties) { |
367
|
6 |
|
$code[] = $associationMappingProperties; |
368
|
6 |
|
} |
369
|
|
|
|
370
|
9 |
|
$code[] = $this->generateDocumentConstructor($metadata); |
371
|
|
|
|
372
|
9 |
|
if ($stubMethods) { |
|
|
|
|
373
|
9 |
|
$code[] = $stubMethods; |
374
|
9 |
|
} |
375
|
|
|
|
376
|
9 |
|
if ($lifecycleCallbackMethods) { |
377
|
6 |
|
$code[] = "\n" . $lifecycleCallbackMethods; |
378
|
6 |
|
} |
379
|
|
|
|
380
|
9 |
|
return implode("\n", $code); |
381
|
|
|
} |
382
|
|
|
|
383
|
9 |
|
private function generateDocumentConstructor(ClassMetadataInfo $metadata) |
384
|
|
|
{ |
385
|
9 |
|
if ($this->hasMethod('__construct', $metadata)) { |
386
|
1 |
|
return ''; |
387
|
|
|
} |
388
|
|
|
|
389
|
9 |
|
$collections = array(); |
390
|
9 |
|
foreach ($metadata->fieldMappings AS $mapping) { |
391
|
9 |
|
if ($mapping['type'] === ClassMetadataInfo::MANY) { |
392
|
6 |
|
$collections[] = '$this->' . $mapping['fieldName'] . ' = new \Doctrine\Common\Collections\ArrayCollection();'; |
393
|
6 |
|
} |
394
|
9 |
|
} |
395
|
9 |
|
if ($collections) { |
|
|
|
|
396
|
6 |
|
return $this->prefixCodeWithSpaces(str_replace("<collections>", $this->spaces . implode("\n" . $this->spaces, $collections), self::$constructorMethodTemplate)); |
397
|
|
|
} |
398
|
3 |
|
return ''; |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* @todo this won't work if there is a namespace in brackets and a class outside of it. |
403
|
|
|
* @param string $path |
404
|
|
|
*/ |
405
|
2 |
|
private function parseTokensInDocumentFile($path) |
406
|
|
|
{ |
407
|
2 |
|
$tokens = token_get_all(file_get_contents($path)); |
408
|
2 |
|
$lastSeenNamespace = ''; |
409
|
2 |
|
$lastSeenClass = false; |
410
|
|
|
|
411
|
2 |
|
for ($i = 0; $i < count($tokens); $i++) { |
|
|
|
|
412
|
2 |
|
$token = $tokens[$i]; |
413
|
2 |
|
if ($token[0] == T_NAMESPACE) { |
414
|
2 |
|
$peek = $i; |
415
|
2 |
|
$lastSeenNamespace = ''; |
416
|
2 |
|
while (isset($tokens[++$peek])) { |
417
|
2 |
|
if (';' == $tokens[$peek]) { |
418
|
2 |
|
break; |
419
|
2 |
|
} elseif (is_array($tokens[$peek]) && in_array($tokens[$peek][0], array(T_STRING, T_NS_SEPARATOR))) { |
420
|
2 |
|
$lastSeenNamespace .= $tokens[$peek][1]; |
421
|
2 |
|
} |
422
|
2 |
|
} |
423
|
2 |
|
} elseif ($token[0] == T_CLASS) { |
424
|
2 |
|
$lastSeenClass = $lastSeenNamespace . '\\' . $tokens[$i + 2][1]; |
425
|
2 |
|
$this->staticReflection[$lastSeenClass]['properties'] = array(); |
426
|
2 |
|
$this->staticReflection[$lastSeenClass]['methods'] = array(); |
427
|
2 |
|
} elseif ($token[0] == T_FUNCTION) { |
428
|
1 |
|
if ($tokens[$i + 2][0] == T_STRING) { |
429
|
1 |
|
$this->staticReflection[$lastSeenClass]['methods'][] = $tokens[$i + 2][1]; |
430
|
1 |
|
} elseif ($tokens[$i + 2][0] == '&' && $tokens[$i + 3][0] == T_STRING) { |
431
|
|
|
$this->staticReflection[$lastSeenClass]['methods'][] = $tokens[$i + 3][1]; |
432
|
|
|
} |
433
|
2 |
|
} elseif (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i + 2][0] != T_FUNCTION) { |
434
|
2 |
|
$this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i + 2][1], 1); |
435
|
2 |
|
} |
436
|
2 |
|
} |
437
|
2 |
|
} |
438
|
|
|
|
439
|
9 |
View Code Duplication |
private function hasProperty($property, ClassMetadataInfo $metadata) |
|
|
|
|
440
|
|
|
{ |
441
|
9 |
|
if ($this->extendsClass() || class_exists($metadata->name)) { |
442
|
|
|
// don't generate property if its already on the base class. |
443
|
2 |
|
$reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name); |
444
|
|
|
|
445
|
2 |
|
if ($reflClass->hasProperty($property)) { |
446
|
1 |
|
return true; |
447
|
|
|
} |
448
|
1 |
|
} |
449
|
|
|
|
450
|
8 |
|
foreach ($this->getTraits($metadata) as $trait) { |
451
|
2 |
|
if ($trait->hasProperty($property)) { |
452
|
2 |
|
return true; |
453
|
|
|
} |
454
|
8 |
|
} |
455
|
|
|
|
456
|
|
|
return ( |
457
|
8 |
|
isset($this->staticReflection[$metadata->name]) && |
458
|
1 |
|
in_array($property, $this->staticReflection[$metadata->name]['properties']) |
459
|
8 |
|
); |
460
|
|
|
} |
461
|
|
|
|
462
|
9 |
View Code Duplication |
private function hasMethod($method, ClassMetadataInfo $metadata) |
|
|
|
|
463
|
|
|
{ |
464
|
9 |
|
if ($this->extendsClass() || class_exists($metadata->name)) { |
465
|
|
|
// don't generate method if its already on the base class. |
466
|
2 |
|
$reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name); |
467
|
|
|
|
468
|
2 |
|
if ($reflClass->hasMethod($method)) { |
469
|
1 |
|
return true; |
470
|
|
|
} |
471
|
2 |
|
} |
472
|
|
|
|
473
|
9 |
|
foreach ($this->getTraits($metadata) as $trait) { |
474
|
2 |
|
if ($trait->hasMethod($method)) { |
475
|
2 |
|
return true; |
476
|
|
|
} |
477
|
9 |
|
} |
478
|
|
|
|
479
|
|
|
return ( |
480
|
9 |
|
isset($this->staticReflection[$metadata->name]) && |
481
|
2 |
|
in_array($method, $this->staticReflection[$metadata->name]['methods']) |
482
|
9 |
|
); |
483
|
|
|
} |
484
|
|
|
|
485
|
8 |
|
private function hasNamespace(ClassMetadataInfo $metadata) |
486
|
|
|
{ |
487
|
8 |
|
return strpos($metadata->name, '\\') ? true : false; |
488
|
|
|
} |
489
|
|
|
|
490
|
9 |
|
private function extendsClass() |
491
|
|
|
{ |
492
|
9 |
|
return $this->classToExtend ? true : false; |
493
|
|
|
} |
494
|
|
|
|
495
|
2 |
|
private function getClassToExtend() |
496
|
|
|
{ |
497
|
2 |
|
return $this->classToExtend; |
498
|
|
|
} |
499
|
|
|
|
500
|
1 |
|
private function getClassToExtendName() |
501
|
|
|
{ |
502
|
1 |
|
$refl = new \ReflectionClass($this->getClassToExtend()); |
503
|
|
|
|
504
|
1 |
|
return '\\' . $refl->getName(); |
505
|
|
|
} |
506
|
|
|
|
507
|
8 |
|
private function getClassName(ClassMetadataInfo $metadata) |
508
|
|
|
{ |
509
|
8 |
|
return ($pos = strrpos($metadata->name, '\\')) |
510
|
8 |
|
? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name; |
511
|
|
|
} |
512
|
|
|
|
513
|
8 |
|
private function getNamespace(ClassMetadataInfo $metadata) |
514
|
|
|
{ |
515
|
8 |
|
return substr($metadata->name, 0, strrpos($metadata->name, '\\')); |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
/** |
519
|
|
|
* @param ClassMetadataInfo $metadata |
520
|
|
|
* |
521
|
|
|
* @return array |
522
|
|
|
*/ |
523
|
9 |
|
protected function getTraits(ClassMetadataInfo $metadata) |
524
|
|
|
{ |
525
|
9 |
|
if (PHP_VERSION_ID >= 50400 && ($metadata->reflClass !== null || class_exists($metadata->name))) { |
526
|
3 |
|
$reflClass = $metadata->reflClass === null ? new \ReflectionClass($metadata->name) : $metadata->reflClass; |
527
|
3 |
|
$traits = array(); |
528
|
3 |
|
while ($reflClass !== false) { |
529
|
3 |
|
$traits = array_merge($traits, $reflClass->getTraits()); |
530
|
3 |
|
$reflClass = $reflClass->getParentClass(); |
531
|
3 |
|
} |
532
|
3 |
|
return $traits; |
533
|
|
|
} |
534
|
6 |
|
return array(); |
535
|
|
|
} |
536
|
|
|
|
537
|
8 |
|
private function generateDocumentImports() |
538
|
|
|
{ |
539
|
8 |
|
if ($this->generateAnnotations) { |
540
|
8 |
|
return 'use Doctrine\\ODM\\MongoDB\\Mapping\\Annotations as ODM;'; |
541
|
|
|
} |
542
|
|
|
} |
543
|
|
|
|
544
|
8 |
|
private function generateDocumentDocBlock(ClassMetadataInfo $metadata) |
545
|
|
|
{ |
546
|
8 |
|
$lines = array(); |
547
|
8 |
|
$lines[] = '/**'; |
548
|
8 |
|
$lines[] = ' * ' . $metadata->name; |
549
|
|
|
|
550
|
8 |
|
if ($this->generateAnnotations) { |
551
|
8 |
|
$lines[] = ' *'; |
552
|
|
|
|
553
|
8 |
|
if ($metadata->isMappedSuperclass) { |
554
|
|
|
$lines[] = ' * @ODM\\MappedSuperclass'; |
555
|
8 |
|
} elseif ($metadata->isEmbeddedDocument) { |
556
|
|
|
$lines[] = ' * @ODM\\EmbeddedDocument'; |
557
|
|
|
} else { |
558
|
8 |
|
$lines[] = ' * @ODM\\Document'; |
559
|
|
|
} |
560
|
|
|
|
561
|
8 |
|
$document = array(); |
562
|
8 |
|
if ( ! $metadata->isMappedSuperclass && ! $metadata->isEmbeddedDocument) { |
563
|
8 |
|
if ($metadata->collection) { |
564
|
8 |
|
$document[] = ' * collection="' . $metadata->collection . '"'; |
565
|
8 |
|
} |
566
|
8 |
|
if ($metadata->customRepositoryClassName) { |
567
|
6 |
|
$document[] = ' * repositoryClass="' . $metadata->customRepositoryClassName . '"'; |
568
|
6 |
|
} |
569
|
8 |
|
} |
570
|
8 |
|
if ($metadata->indexes) { |
|
|
|
|
571
|
|
|
$indexes = array(); |
572
|
|
|
$indexLines = array(); |
573
|
|
|
$indexLines[] = " * indexes={"; |
574
|
|
|
foreach ($metadata->indexes as $index) { |
575
|
|
|
$keys = array(); |
576
|
|
View Code Duplication |
foreach ($index['keys'] as $key => $value) { |
|
|
|
|
577
|
|
|
$keys[] = '"' . $key . '"="' . $value . '"'; |
578
|
|
|
} |
579
|
|
|
$options = array(); |
580
|
|
View Code Duplication |
foreach ($index['options'] as $key => $value) { |
|
|
|
|
581
|
|
|
$options[] = '"' . $key . '"="' . $value . '"'; |
582
|
|
|
} |
583
|
|
|
$indexes[] = '@ODM\\Index(keys={' . implode(', ', $keys) . '}, options={' . implode(', ', $options) . '})'; |
584
|
|
|
} |
585
|
|
|
$indexLines[] = "\n * " . implode(",\n * ", $indexes); |
586
|
|
|
$indexLines[] = "\n * }"; |
587
|
|
|
|
588
|
|
|
$document[] = implode(null, $indexLines); |
589
|
|
|
} |
590
|
|
|
|
591
|
8 |
|
if ($document) { |
|
|
|
|
592
|
8 |
|
$lines[count($lines) - 1] .= '('; |
593
|
8 |
|
$lines[] = implode(",\n", $document); |
594
|
8 |
|
$lines[] = ' * )'; |
595
|
8 |
|
} |
596
|
|
|
|
597
|
8 |
|
if ( ! empty($metadata->lifecycleCallbacks)) { |
598
|
6 |
|
$lines[] = ' * @ODM\HasLifecycleCallbacks'; |
599
|
6 |
|
} |
600
|
|
|
|
601
|
|
|
$methods = array( |
602
|
8 |
|
'generateInheritanceAnnotation', |
603
|
8 |
|
'generateDiscriminatorFieldAnnotation', |
604
|
8 |
|
'generateDiscriminatorMapAnnotation', |
605
|
8 |
|
'generateDefaultDiscriminatorValueAnnotation', |
606
|
|
|
'generateChangeTrackingPolicyAnnotation' |
607
|
8 |
|
); |
608
|
|
|
|
609
|
8 |
|
foreach ($methods as $method) { |
610
|
8 |
|
if ($code = $this->$method($metadata)) { |
611
|
8 |
|
$lines[] = ' * ' . $code; |
612
|
8 |
|
} |
613
|
8 |
|
} |
614
|
8 |
|
} |
615
|
|
|
|
616
|
8 |
|
$lines[] = ' */'; |
617
|
8 |
|
return implode("\n", $lines); |
618
|
|
|
} |
619
|
|
|
|
620
|
8 |
|
private function generateInheritanceAnnotation(ClassMetadataInfo $metadata) |
621
|
|
|
{ |
622
|
8 |
|
if ($metadata->inheritanceType !== ClassMetadataInfo::INHERITANCE_TYPE_NONE) { |
623
|
|
|
return '@ODM\\InheritanceType("' . $this->getInheritanceTypeString($metadata->inheritanceType) . '")'; |
624
|
|
|
} |
625
|
8 |
|
} |
626
|
|
|
|
627
|
8 |
|
private function generateDiscriminatorFieldAnnotation(ClassMetadataInfo $metadata) |
628
|
|
|
{ |
629
|
8 |
|
if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) { |
630
|
|
|
return '@ODM\\DiscriminatorField(name="' . $metadata->discriminatorField . '")'; |
631
|
|
|
} |
632
|
8 |
|
} |
633
|
|
|
|
634
|
8 |
|
private function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata) |
635
|
|
|
{ |
636
|
8 |
|
if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) { |
637
|
|
|
$inheritanceClassMap = array(); |
638
|
|
|
|
639
|
|
|
foreach ($metadata->discriminatorMap as $type => $class) { |
640
|
|
|
$inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"'; |
641
|
|
|
} |
642
|
|
|
|
643
|
|
|
return '@ODM\\DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})'; |
644
|
|
|
} |
645
|
8 |
|
} |
646
|
|
|
|
647
|
8 |
|
private function generateDefaultDiscriminatorValueAnnotation(ClassMetadataInfo $metadata) |
648
|
|
|
{ |
649
|
8 |
|
if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION && isset($metadata->defaultDiscriminatorValue)) { |
650
|
|
|
return '@ODM\\DefaultDiscriminatorValue("' . $metadata->defaultDiscriminatorValue . '")'; |
651
|
|
|
} |
652
|
8 |
|
} |
653
|
|
|
|
654
|
8 |
|
private function generateChangeTrackingPolicyAnnotation(ClassMetadataInfo $metadata) |
655
|
|
|
{ |
656
|
8 |
|
return '@ODM\\ChangeTrackingPolicy("' . $this->getChangeTrackingPolicyString($metadata->changeTrackingPolicy) . '")'; |
657
|
|
|
} |
658
|
|
|
|
659
|
9 |
|
private function generateDocumentStubMethods(ClassMetadataInfo $metadata) |
660
|
|
|
{ |
661
|
9 |
|
$methods = array(); |
662
|
|
|
|
663
|
9 |
|
foreach ($metadata->fieldMappings as $fieldMapping) { |
664
|
9 |
|
if (isset($fieldMapping['id'])) { |
665
|
9 |
|
if ($metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE) { |
666
|
|
|
if ($code = $this->generateDocumentStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) { |
667
|
|
|
$methods[] = $code; |
668
|
|
|
} |
669
|
|
|
} |
670
|
9 |
|
if ($code = $code = $this->generateDocumentStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) { |
671
|
8 |
|
$methods[] = $code; |
672
|
8 |
|
} |
673
|
9 |
|
} elseif ( ! isset($fieldMapping['association'])) { |
674
|
9 |
|
if ($code = $code = $this->generateDocumentStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) { |
675
|
9 |
|
$methods[] = $code; |
676
|
9 |
|
} |
677
|
9 |
|
if ($code = $code = $this->generateDocumentStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) { |
678
|
9 |
|
$methods[] = $code; |
679
|
9 |
|
} |
680
|
9 |
|
} elseif ($fieldMapping['type'] === ClassMetadataInfo::ONE) { |
681
|
8 |
|
$nullable = $this->isAssociationNullable($fieldMapping) ? 'null' : null; |
682
|
8 |
View Code Duplication |
if ($code = $this->generateDocumentStubMethod($metadata, 'set', $fieldMapping['fieldName'], isset($fieldMapping['targetDocument']) ? $fieldMapping['targetDocument'] : null, $nullable)) { |
|
|
|
|
683
|
6 |
|
$methods[] = $code; |
684
|
6 |
|
} |
685
|
8 |
View Code Duplication |
if ($code = $this->generateDocumentStubMethod($metadata, 'get', $fieldMapping['fieldName'], isset($fieldMapping['targetDocument']) ? $fieldMapping['targetDocument'] : null)) { |
|
|
|
|
686
|
6 |
|
$methods[] = $code; |
687
|
6 |
|
} |
688
|
8 |
|
} elseif ($fieldMapping['type'] === ClassMetadataInfo::MANY) { |
689
|
6 |
View Code Duplication |
if ($code = $this->generateDocumentStubMethod($metadata, 'add', $fieldMapping['fieldName'], isset($fieldMapping['targetDocument']) ? $fieldMapping['targetDocument'] : null)) { |
|
|
|
|
690
|
6 |
|
$methods[] = $code; |
691
|
6 |
|
} |
692
|
6 |
View Code Duplication |
if ($code = $this->generateDocumentStubMethod($metadata, 'remove', $fieldMapping['fieldName'], isset($fieldMapping['targetDocument']) ? $fieldMapping['targetDocument'] : null)) { |
|
|
|
|
693
|
6 |
|
$methods[] = $code; |
694
|
6 |
|
} |
695
|
6 |
|
if ($code = $this->generateDocumentStubMethod($metadata, 'get', $fieldMapping['fieldName'], '\Doctrine\Common\Collections\Collection')) { |
696
|
6 |
|
$methods[] = $code; |
697
|
6 |
|
} |
698
|
6 |
|
} |
699
|
9 |
|
} |
700
|
|
|
|
701
|
9 |
|
return implode("\n\n", $methods); |
702
|
|
|
} |
703
|
|
|
|
704
|
|
|
/** |
705
|
|
|
* @param array $fieldMapping |
706
|
|
|
* |
707
|
|
|
* @return bool |
708
|
|
|
*/ |
709
|
8 |
|
protected function isAssociationNullable($fieldMapping) |
710
|
|
|
{ |
711
|
8 |
|
return isset($fieldMapping['nullable']) && $fieldMapping['nullable']; |
712
|
|
|
} |
713
|
|
|
|
714
|
9 |
|
private function generateDocumentLifecycleCallbackMethods(ClassMetadataInfo $metadata) |
715
|
|
|
{ |
716
|
9 |
|
if (empty($metadata->lifecycleCallbacks)) { |
717
|
3 |
|
return ''; |
718
|
|
|
} |
719
|
|
|
|
720
|
6 |
|
$methods = array(); |
721
|
|
|
|
722
|
6 |
|
foreach ($metadata->lifecycleCallbacks as $event => $callbacks) { |
723
|
6 |
|
foreach ($callbacks as $callback) { |
724
|
6 |
|
if ($code = $this->generateLifecycleCallbackMethod($event, $callback, $metadata)) { |
725
|
6 |
|
$methods[] = $code; |
726
|
6 |
|
} |
727
|
6 |
|
} |
728
|
6 |
|
} |
729
|
|
|
|
730
|
6 |
|
return implode("\n\n", $methods); |
731
|
|
|
} |
732
|
|
|
|
733
|
9 |
|
private function generateDocumentAssociationMappingProperties(ClassMetadataInfo $metadata) |
734
|
|
|
{ |
735
|
9 |
|
$lines = array(); |
736
|
|
|
|
737
|
9 |
|
foreach ($metadata->fieldMappings as $fieldMapping) { |
738
|
9 |
|
if ($this->hasProperty($fieldMapping['fieldName'], $metadata) || |
739
|
9 |
|
$metadata->isInheritedField($fieldMapping['fieldName'])) { |
740
|
4 |
|
continue; |
741
|
|
|
} |
742
|
7 |
|
if ( ! isset($fieldMapping['association'])) { |
743
|
7 |
|
continue; |
744
|
|
|
} |
745
|
|
|
|
746
|
6 |
|
$lines[] = $this->generateAssociationMappingPropertyDocBlock($fieldMapping, $metadata); |
|
|
|
|
747
|
6 |
|
$lines[] = $this->spaces . 'protected $' . $fieldMapping['fieldName'] |
748
|
6 |
|
. ($fieldMapping['type'] === ClassMetadataInfo::MANY ? ' = array()' : null) . ";\n"; |
749
|
9 |
|
} |
750
|
|
|
|
751
|
9 |
|
return implode("\n", $lines); |
752
|
|
|
} |
753
|
|
|
|
754
|
9 |
|
private function generateDocumentFieldMappingProperties(ClassMetadataInfo $metadata) |
755
|
|
|
{ |
756
|
9 |
|
$lines = array(); |
757
|
|
|
|
758
|
9 |
|
foreach ($metadata->fieldMappings as $fieldMapping) { |
759
|
9 |
|
if ($this->hasProperty($fieldMapping['fieldName'], $metadata) || |
760
|
9 |
|
$metadata->isInheritedField($fieldMapping['fieldName'])) { |
761
|
4 |
|
continue; |
762
|
|
|
} |
763
|
7 |
|
if (isset($fieldMapping['association']) && $fieldMapping['association']) { |
764
|
6 |
|
continue; |
765
|
|
|
} |
766
|
|
|
|
767
|
7 |
|
$lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata); |
768
|
7 |
|
$lines[] = $this->spaces . 'protected $' . $fieldMapping['fieldName'] |
769
|
7 |
|
. (isset($fieldMapping['default']) ? ' = ' . var_export($fieldMapping['default'], true) : null) . ";\n"; |
770
|
9 |
|
} |
771
|
|
|
|
772
|
9 |
|
return implode("\n", $lines); |
773
|
|
|
} |
774
|
|
|
|
775
|
9 |
|
private function generateDocumentStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null) |
776
|
|
|
{ |
777
|
|
|
// Add/remove methods should use the singular form of the field name |
778
|
9 |
|
$formattedFieldName = in_array($type, array('add', 'remove')) |
779
|
9 |
|
? Inflector::singularize($fieldName) |
780
|
9 |
|
: $fieldName; |
781
|
|
|
|
782
|
9 |
|
$methodName = $type . Inflector::classify($formattedFieldName); |
783
|
9 |
|
$variableName = Inflector::camelize($formattedFieldName); |
784
|
|
|
|
785
|
9 |
|
if ($this->hasMethod($methodName, $metadata)) { |
786
|
4 |
|
return; |
787
|
|
|
} |
788
|
|
|
|
789
|
9 |
|
$description = ucfirst($type) . ' ' . $variableName; |
790
|
|
|
|
791
|
9 |
|
$types = Type::getTypesMap(); |
792
|
9 |
|
$methodTypeHint = $typeHint && ! isset($types[$typeHint]) ? '\\' . $typeHint . ' ' : null; |
793
|
9 |
|
$variableType = $typeHint ? $typeHint . ' ' : null; |
794
|
|
|
|
795
|
|
|
$replacements = array( |
796
|
9 |
|
'<description>' => $description, |
797
|
9 |
|
'<methodTypeHint>' => $methodTypeHint, |
798
|
9 |
|
'<variableType>' => $variableType, |
799
|
9 |
|
'<variableName>' => $variableName, |
800
|
9 |
|
'<methodName>' => $methodName, |
801
|
9 |
|
'<fieldName>' => $fieldName, |
802
|
9 |
|
'<variableDefault>' => ($defaultValue !== null ) ? (' = ' . $defaultValue) : '', |
803
|
9 |
|
); |
804
|
|
|
|
805
|
9 |
|
$templateVar = sprintf('%sMethodTemplate', $type); |
806
|
|
|
|
807
|
9 |
|
$method = str_replace( |
808
|
9 |
|
array_keys($replacements), |
809
|
9 |
|
array_values($replacements), |
810
|
|
|
self::$$templateVar |
811
|
9 |
|
); |
812
|
|
|
|
813
|
9 |
|
return $this->prefixCodeWithSpaces($method); |
814
|
|
|
} |
815
|
|
|
|
816
|
6 |
|
private function generateLifecycleCallbackMethod($name, $methodName, ClassMetadataInfo $metadata) |
817
|
|
|
{ |
818
|
6 |
|
if ($this->hasMethod($methodName, $metadata)) { |
819
|
1 |
|
return; |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
$replacements = array( |
823
|
6 |
|
'<comment>' => $this->generateAnnotations ? '/** @ODM\\' . ucfirst($name) . ' */' : '', |
824
|
6 |
|
'<methodName>' => $methodName, |
825
|
6 |
|
); |
826
|
|
|
|
827
|
6 |
|
$method = str_replace( |
828
|
6 |
|
array_keys($replacements), |
829
|
6 |
|
array_values($replacements), |
830
|
|
|
self::$lifecycleCallbackMethodTemplate |
831
|
6 |
|
); |
832
|
|
|
|
833
|
6 |
|
return $this->prefixCodeWithSpaces($method); |
834
|
|
|
} |
835
|
|
|
|
836
|
6 |
|
private function generateAssociationMappingPropertyDocBlock(array $fieldMapping) |
837
|
|
|
{ |
838
|
6 |
|
$lines = array(); |
839
|
6 |
|
$lines[] = $this->spaces . '/**'; |
840
|
6 |
|
$lines[] = $this->spaces . ' * @var ' . (isset($fieldMapping['targetDocument']) ? $fieldMapping['targetDocument'] : 'object'); |
841
|
|
|
|
842
|
6 |
|
if ($this->generateAnnotations) { |
843
|
6 |
|
$lines[] = $this->spaces . ' *'; |
844
|
|
|
|
845
|
6 |
|
$type = null; |
846
|
6 |
|
switch ($fieldMapping['association']) { |
847
|
6 |
|
case ClassMetadataInfo::EMBED_ONE: |
848
|
|
|
$type = 'EmbedOne'; |
849
|
|
|
break; |
850
|
6 |
|
case ClassMetadataInfo::EMBED_MANY: |
851
|
|
|
$type = 'EmbedMany'; |
852
|
|
|
break; |
853
|
6 |
|
case ClassMetadataInfo::REFERENCE_ONE: |
854
|
6 |
|
$type = 'ReferenceOne'; |
855
|
6 |
|
break; |
856
|
6 |
|
case ClassMetadataInfo::REFERENCE_MANY: |
857
|
6 |
|
$type = 'ReferenceMany'; |
858
|
6 |
|
break; |
859
|
6 |
|
} |
860
|
6 |
|
$typeOptions = array(); |
861
|
|
|
|
862
|
6 |
|
if (isset($fieldMapping['targetDocument'])) { |
863
|
6 |
|
$typeOptions[] = 'targetDocument="' . $fieldMapping['targetDocument'] . '"'; |
864
|
6 |
|
} |
865
|
|
|
|
866
|
6 |
|
if (isset($fieldMapping['cascade']) && $fieldMapping['cascade']) { |
867
|
|
|
$cascades = array(); |
868
|
|
|
|
869
|
|
|
if ($fieldMapping['isCascadePersist']) $cascades[] = '"persist"'; |
870
|
|
|
if ($fieldMapping['isCascadeRemove']) $cascades[] = '"remove"'; |
871
|
|
|
if ($fieldMapping['isCascadeDetach']) $cascades[] = '"detach"'; |
872
|
|
|
if ($fieldMapping['isCascadeMerge']) $cascades[] = '"merge"'; |
873
|
|
|
if ($fieldMapping['isCascadeRefresh']) $cascades[] = '"refresh"'; |
874
|
|
|
|
875
|
|
|
$typeOptions[] = 'cascade={' . implode(',', $cascades) . '}'; |
876
|
|
|
} |
877
|
|
|
|
878
|
6 |
|
$lines[] = $this->spaces . ' * @ODM\\' . $type . '(' . implode(', ', $typeOptions) . ')'; |
879
|
6 |
|
} |
880
|
|
|
|
881
|
6 |
|
$lines[] = $this->spaces . ' */'; |
882
|
|
|
|
883
|
6 |
|
return implode("\n", $lines); |
884
|
|
|
} |
885
|
|
|
|
886
|
7 |
|
private function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata) |
887
|
|
|
{ |
888
|
7 |
|
$lines = array(); |
889
|
7 |
|
$lines[] = $this->spaces . '/**'; |
890
|
7 |
|
if (isset($fieldMapping['id']) && $fieldMapping['id']) { |
891
|
7 |
|
$fieldMapping['strategy'] = isset($fieldMapping['strategy']) ? $fieldMapping['strategy'] : ClassMetadataInfo::GENERATOR_TYPE_AUTO; |
892
|
7 |
|
if ($fieldMapping['strategy'] === ClassMetadataInfo::GENERATOR_TYPE_AUTO) { |
893
|
6 |
|
$lines[] = $this->spaces . ' * @var MongoId $' . $fieldMapping['fieldName']; |
894
|
7 |
View Code Duplication |
} elseif ($fieldMapping['strategy'] === ClassMetadataInfo::GENERATOR_TYPE_INCREMENT) { |
|
|
|
|
895
|
|
|
$lines[] = $this->spaces . ' * @var integer $' . $fieldMapping['fieldName']; |
896
|
1 |
|
} elseif ($fieldMapping['strategy'] === ClassMetadataInfo::GENERATOR_TYPE_UUID) { |
897
|
|
|
$lines[] = $this->spaces . ' * @var string $' . $fieldMapping['fieldName']; |
898
|
1 |
View Code Duplication |
} elseif ($fieldMapping['strategy'] === ClassMetadataInfo::GENERATOR_TYPE_NONE) { |
|
|
|
|
899
|
|
|
$lines[] = $this->spaces . ' * @var $' . $fieldMapping['fieldName']; |
900
|
|
|
} else { |
901
|
1 |
|
$lines[] = $this->spaces . ' * @var $' . $fieldMapping['fieldName']; |
902
|
|
|
} |
903
|
7 |
|
} else { |
904
|
7 |
|
$lines[] = $this->spaces . ' * @var ' . $fieldMapping['type'] . ' $' . $fieldMapping['fieldName']; |
905
|
|
|
} |
906
|
|
|
|
907
|
7 |
|
if ($this->generateAnnotations) { |
908
|
7 |
|
$lines[] = $this->spaces . ' *'; |
909
|
|
|
|
910
|
7 |
|
$field = array(); |
911
|
7 |
|
if (isset($fieldMapping['id']) && $fieldMapping['id']) { |
912
|
7 |
|
if (isset($fieldMapping['strategy'])) { |
913
|
7 |
|
$field[] = 'strategy="' . $this->getIdGeneratorTypeString($metadata->generatorType) . '"'; |
914
|
7 |
|
} |
915
|
7 |
|
$lines[] = $this->spaces . ' * @ODM\\Id(' . implode(', ', $field) . ')'; |
916
|
7 |
|
} else { |
917
|
7 |
|
if (isset($fieldMapping['name'])) { |
918
|
7 |
|
$field[] = 'name="' . $fieldMapping['name'] . '"'; |
919
|
7 |
|
} |
920
|
|
|
|
921
|
7 |
|
if (isset($fieldMapping['type'])) { |
922
|
7 |
|
$field[] = 'type="' . $fieldMapping['type'] . '"'; |
923
|
7 |
|
} |
924
|
|
|
|
925
|
7 |
|
if (isset($fieldMapping['nullable']) && $fieldMapping['nullable'] === true) { |
926
|
|
|
$field[] = 'nullable=' . var_export($fieldMapping['nullable'], true); |
927
|
|
|
} |
928
|
7 |
|
if (isset($fieldMapping['options'])) { |
929
|
1 |
|
$options = array(); |
930
|
1 |
|
foreach ($fieldMapping['options'] as $key => $value) { |
931
|
|
|
$options[] = '"' . $key . '" = "' . $value . '"'; |
932
|
1 |
|
} |
933
|
1 |
|
$field[] = "options={" . implode(', ', $options) . "}"; |
934
|
1 |
|
} |
935
|
7 |
|
$lines[] = $this->spaces . ' * @ODM\\Field(' . implode(', ', $field) . ')'; |
936
|
|
|
} |
937
|
|
|
|
938
|
7 |
|
if (isset($fieldMapping['version']) && $fieldMapping['version']) { |
939
|
|
|
$lines[] = $this->spaces . ' * @ODM\\Version'; |
940
|
|
|
} |
941
|
7 |
|
} |
942
|
|
|
|
943
|
7 |
|
$lines[] = $this->spaces . ' */'; |
944
|
|
|
|
945
|
7 |
|
return implode("\n", $lines); |
946
|
|
|
} |
947
|
|
|
|
948
|
9 |
|
private function prefixCodeWithSpaces($code, $num = 1) |
949
|
|
|
{ |
950
|
9 |
|
$lines = explode("\n", $code); |
951
|
|
|
|
952
|
9 |
|
foreach ($lines as $key => $value) { |
953
|
9 |
|
$lines[$key] = str_repeat($this->spaces, $num) . $lines[$key]; |
954
|
9 |
|
} |
955
|
|
|
|
956
|
9 |
|
return implode("\n", $lines); |
957
|
|
|
} |
958
|
|
|
|
959
|
|
|
private function getInheritanceTypeString($type) |
960
|
|
|
{ |
961
|
|
|
switch ($type) { |
962
|
|
|
case ClassMetadataInfo::INHERITANCE_TYPE_NONE: |
963
|
|
|
return 'NONE'; |
964
|
|
|
|
965
|
|
|
case ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION: |
966
|
|
|
return 'SINGLE_COLLECTION'; |
967
|
|
|
|
968
|
|
|
case ClassMetadataInfo::INHERITANCE_TYPE_COLLECTION_PER_CLASS: |
969
|
|
|
return 'COLLECTION_PER_CLASS'; |
970
|
|
|
|
971
|
|
|
default: |
972
|
|
|
throw new \InvalidArgumentException('Invalid provided InheritanceType: ' . $type); |
973
|
|
|
} |
974
|
|
|
} |
975
|
|
|
|
976
|
8 |
|
private function getChangeTrackingPolicyString($policy) |
977
|
|
|
{ |
978
|
|
|
switch ($policy) { |
979
|
8 |
|
case ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT: |
980
|
8 |
|
return 'DEFERRED_IMPLICIT'; |
981
|
|
|
|
982
|
|
|
case ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT: |
983
|
|
|
return 'DEFERRED_EXPLICIT'; |
984
|
|
|
|
985
|
|
|
case ClassMetadataInfo::CHANGETRACKING_NOTIFY: |
986
|
|
|
return 'NOTIFY'; |
987
|
|
|
|
988
|
|
|
default: |
989
|
|
|
throw new \InvalidArgumentException('Invalid provided ChangeTrackingPolicy: ' . $policy); |
990
|
|
|
} |
991
|
|
|
} |
992
|
|
|
|
993
|
7 |
|
private function getIdGeneratorTypeString($type) |
994
|
|
|
{ |
995
|
|
|
switch ($type) { |
996
|
7 |
|
case ClassMetadataInfo::GENERATOR_TYPE_AUTO: |
997
|
1 |
|
return 'AUTO'; |
998
|
|
|
|
999
|
6 |
|
case ClassMetadataInfo::GENERATOR_TYPE_INCREMENT: |
1000
|
|
|
return 'INCREMENT'; |
1001
|
|
|
|
1002
|
6 |
|
case ClassMetadataInfo::GENERATOR_TYPE_UUID: |
1003
|
|
|
return 'UUID'; |
1004
|
|
|
|
1005
|
6 |
|
case ClassMetadataInfo::GENERATOR_TYPE_ALNUM: |
1006
|
|
|
return 'ALNUM'; |
1007
|
|
|
|
1008
|
6 |
|
case ClassMetadataInfo::GENERATOR_TYPE_CUSTOM: |
1009
|
6 |
|
return 'CUSTOM'; |
1010
|
|
|
|
1011
|
|
|
case ClassMetadataInfo::GENERATOR_TYPE_NONE: |
1012
|
|
|
return 'NONE'; |
1013
|
|
|
|
1014
|
|
|
default: |
1015
|
|
|
throw new \InvalidArgumentException('Invalid provided IdGeneratorType: ' . $type); |
1016
|
|
|
} |
1017
|
|
|
} |
1018
|
|
|
} |
1019
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.