Completed
Pull Request — 2.1 (#53)
by
unknown
01:08
created

EntitiesGeneratorService::generateAll()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 8.9848
c 0
b 0
f 0
cc 5
nc 8
nop 2
1
<?php
2
3
namespace Wabel\Zoho\CRM\Service;
4
5
use gossi\codegen\generator\CodeFileGenerator;
6
use gossi\codegen\model\PhpClass;
7
use gossi\codegen\model\PhpMethod;
8
use gossi\codegen\model\PhpParameter;
9
use gossi\codegen\model\PhpProperty;
10
use Psr\Log\LoggerInterface;
11
use Wabel\Zoho\CRM\Exceptions\ZohoCRMORMException;
12
use Wabel\Zoho\CRM\ZohoClient;
13
use zcrmsdk\crm\crud\ZCRMModule;
14
use zcrmsdk\crm\crud\ZCRMPickListValue;
15
use zcrmsdk\crm\crud\ZCRMField;
16
17
18
/**
19
 * This class is in charge of generating Zoho entities.
20
 */
21
class EntitiesGeneratorService
22
{
23
    private $zohoClient;
24
    private $logger;
25
26
    public static $defaultZohoFields = ['Created_Time','Modified_Time', 'Last_Activity_Time',
27
        'Created_By', 'Modified_By', 'Owner'];
28
29
    public static $defaultORMFields = ['createdTime','modifiedTime', 'lastActivityTime',
30
        'createdByID', 'modifiedByID', 'createdByName', 'modifiedByName', 'OwnerID', 'OwnerName',
31
        'ZCRMRecord'
32
    ];
33
34
    public static $defaultORMSystemFields = ['createdTime','modifiedTime', 'lastActivityTime',
35
        'ZCRMRecord', 'zohoId'
36
    ];
37
38
    public static $defaultDateFields = ['createdTime','modifiedTime', 'lastActivityTime'];
39
40
    public function __construct(ZohoClient $zohoClient, LoggerInterface $logger)
41
    {
42
        $this->zohoClient = $zohoClient;
43
        $this->logger = $logger;
44
    }
45
46
    /**
47
     * Generate ALL entities for all Zoho modules.
48
     *
49
     * @param string $targetDirectory
50
     * @param string $namespace
51
     *
52
     * @return array Array containing each fully qualified dao class name
53
     */
54
    public function generateAll($targetDirectory, $namespace)
55
    {
56
        /**
57
         * @var $modules ZCRMModule[]
58
         */
59
        $modules = $this->zohoClient->getModules();
60
        $this->logger->debug(sprintf('%d modules received', count($modules)));
61
        $zohoModules = [];
62
        foreach ($modules as $module) {
63
            $this->logger->debug(sprintf('Generating module %s', $module->getAPIName()));
64
            if ($module->isApiSupported()) {
65
                try {
66
                    $generatedModule = $this->generateModule(
67
                        $module->getAPIName(), $module->getAPIName(),
68
                        substr($module->getAPIName(), 0, -1), $targetDirectory, $namespace
69
                    );
70
                    if ($generatedModule) {
71
                        $zohoModules[] = $generatedModule;
72
                        $this->logger->info(sprintf('Module %s has been generated.', $module->getAPIName()));
73
                    } else {
74
                        $this->logger->warning(sprintf('Module %s could not be generated.', $module->getAPIName()));
75
                    }
76
                } catch (ZohoCRMORMException $e) {
77
                    $this->logger->notice(
78
                        'Error thrown when retrieving fields for module {module}. Error message: {error}.',
79
                        [
80
                            'module' => $module->getAPIName(),
81
                            'error' => $e->getMessage(),
82
                            'exception' => $e,
83
                        ]
84
                    );
85
                }
86
            } else {
87
                $this->logger->debug(sprintf('Module %s does not support API. Generation skipped.', $module->getAPIName()));
88
            }
89
        }
90
91
        return $zohoModules;
92
    }
93
94
    /**
95
     * Generate a dao for a zoho module.
96
     *
97
     * @param string $moduleName
98
     * @param string $modulePlural
99
     * @param string $moduleSingular
100
     * @param string $targetDirectory
101
     * @param string $namespace
102
     *
103
     * @return string|null The fully qualified Dao class name
104
     */
105
    public function generateModule($moduleName, $modulePlural, $moduleSingular, $targetDirectory, $namespace)
106
    {
107
        $fieldRecords = $this->zohoClient->getFields($moduleName);
108
109
        if(!$fieldRecords) {
110
            return null;
111
        }
112
        if (!file_exists($targetDirectory)) {
113
            mkdir($targetDirectory, 0775, true);
114
        }
115
116
        $namespace = trim($namespace, '\\');
117
        $className = self::upperCamelCase($moduleSingular);
118
        $daoClassName = $className.'ZohoDao';
119
120
121
        // Case is a reserved keyword. Let's rename it.
122
        if ($className === 'Case') {
123
            $className = 'ZohoCase';
124
        }
125
126
        $this->generateBean($fieldRecords, $namespace, $className, $moduleName, $targetDirectory, $moduleSingular);
0 ignored issues
show
Documentation introduced by
$fieldRecords is of type object, but the function expects a array<integer,object<zcrmsdk\crm\crud\ZCRMField>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127
        $this->generateDao($fieldRecords, $namespace, $className, $daoClassName, $moduleName, $targetDirectory, $moduleSingular, $modulePlural);
0 ignored issues
show
Documentation introduced by
$fieldRecords is of type object, but the function expects a array<integer,object<zcrmsdk\crm\crud\ZCRMField>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
128
129
        return $namespace.'\\'.$daoClassName;
130
    }
131
132
    /**
133
     * @param  ZCRMField[] $ZCRMfields
134
     * @param  string       $namespace
135
     * @param  string       $className
136
     * @param  string       $moduleName
137
     * @param  string       $targetDirectory
138
     * @param  string       $moduleSingular
139
     * @throws ZohoCRMORMException
140
     */
141
    public function generateBean(array $ZCRMfields, $namespace, $className, $moduleName, $targetDirectory, $moduleSingular)
0 ignored issues
show
Unused Code introduced by
The parameter $moduleName is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $moduleSingular is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
142
    {
143
144
        $class = PhpClass::create();
145
        $class->setName($className)
146
            ->setNamespace($namespace)
147
            ->addInterface('\\Wabel\\Zoho\\CRM\\ZohoBeanInterface')
148
            ->setMethod(PhpMethod::create('__construct'));
149
150
        // Let's add the ZohoID property
151
        self::registerProperty($class, 'zohoId', "The ID of this record in Zoho\nType: string\n", 'string');
152
153
        foreach ($ZCRMfields as $ZCRMfield) {
154
            $name = self::camelCase($ZCRMfield->getApiName());
155
            $apiName = $ZCRMfield->getApiName();
156
            $type = $ZCRMfield->getDataType();
157
            $isreadonly = $ZCRMfield->isReadOnly();
158
            $maxlength = $ZCRMfield->getLength();
159
            $label = $ZCRMfield->getFieldLabel();
160
            $customfield = $ZCRMfield->isCustomField();
161
            $nullable = false;
162
            switch ($type) {
163
            case 'datetime':
164
            case 'date':
165
                $phpType = '\\DateTimeInterface';
166
                $nullable = true;
167
                break;
168
            case 'boolean':
169
                $phpType = 'bool';
170
                break;
171
            case 'bigint':
172
            case 'integer':
173
            case 'autonumber':
174
                $phpType = 'int';
175
                break;
176
            case 'currency':
177
            case 'decimal':
178
            case 'double':
179
            case 'percent':
180
                $phpType = 'float';
181
                break;
182
            case 'multiselectpicklist':
183
                $phpType = 'string[]';
184
                $nullable = true;
185
                break;
186
            case 'picklist':
187
                $phpType = 'string';
188
                $nullable = true;
189
                break;
190
            case 'ownerlookup':
191
                $name = self::camelCase($name.'_OwnerID');
192
                $phpType = 'string';
193
                break;
194
            case 'lookup':
195
                $name = self::camelCase($name.'_ID');
196
                $phpType = 'string';
197
                break;
198
            case 'multiselectlookup':
199
                continue 2;
200
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
201
            case 'userlookup':
202
                $name = self::camelCase($name.'_UserID');
203
                $phpType = 'string';
204
                $nullable = true;
205
                break;
206
            case 'multiuserlookup':
207
                //@Todo: It's a hypothetical field name based on zoho fields architecture
208
                $name = self::camelCase($name.'_UserIDs');
209
                $phpType = 'string[]';
210
                $nullable = true;
211
                break;
212
            case 'fileupload':
213
                $phpType = 'text';
214
                break;
215
            case 'consent_lookup':
216
            case 'profileimage':
217
            case 'ALARM':
218
            case 'RRULE':
219
            case 'event_reminder':
220
                //@Todo: We have to see how we can work with it
221
                continue 2;
222
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
223
            default:
224
                $phpType = 'string';
225
                break;
226
            }
227
            if(in_array($name, self::$defaultDateFields)) {
228
                //Zoho provides these fields by ZCRMRecord::getFieldValue() but also by method in ZCRMRecord
229
                $phpType = '\\DateTimeImmutable';
230
                $nullable = true;
231
            }
232
233
            self::registerProperty(
234
                $class, $name, 'Zoho field '.$label."\n".
235
                'Field API Name: '.$apiName."\n".
236
                'Type: '.$type."\n".
237
                'Read only: '.($isreadonly ? 'true' : 'false')."\n".
238
                'Max length: '.$maxlength."\n".
239
                'Custom field: '.($customfield ? 'true' : 'false')."\n", $phpType, $nullable
240
            );
241
        }
242
243
        /**
244
         * If Zoho provides them we don't have to create them again
245
         */
246
        self::registerProperty($class, 'createdTime', "The time the record was created in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
247
        self::registerProperty($class, 'modifiedTime', "The last time the record was modified in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
248
        self::registerProperty($class, 'lastActivityTime', "The last activity time the record or a related record was modified in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
249
        self::registerProperty($class, 'createdByOwnerID', "The user id who created the entity in Zoho\nType: string\n", 'string');
250
        self::registerProperty($class, 'modifiedByOwnerID', "The user id who modified the entity in Zoho\nType: string\n", 'string');
251
        self::registerProperty($class, 'createdByOwnerName', "The user id who created the entity in Zoho\nType: string\n", 'string');
252
        self::registerProperty($class, 'modifiedByOwnerName', "The user id who modified the entity in Zoho\nType: string\n", 'string');
253
        self::registerProperty($class, 'ownerOwnerID', "Owner ID in Zoho: string\n", 'string');
254
        self::registerProperty($class, 'ownerOwnerName', "Owner Name in Zoho: string\n", 'string');
255
        self::registerProperty($class, 'ZCRMRecord', "The Wrapped Zoho CRM Record\nType: ZCRMRecord\n", '\\zcrmsdk\\crm\\crud\\ZCRMRecord');
256
        $methodIsDirty = PhpMethod::create('isDirty');
257
        $methodIsDirty->setDescription('Returns whether a property is changed or not.');
258
        $methodIsDirty->addParameter(PhpParameter::create('name'));
259
        $methodIsDirty->setBody("\$propertyName = 'dirty'.ucfirst(\$name);\nreturn \$this->\$propertyName;");
260
        $methodIsDirty->setType('bool');
261
        $class->setMethod($methodIsDirty);
262
        $methodSetDirty = PhpMethod::create('setDirty');
263
        $methodSetDirty->setDescription('Returns whether a property is changed or not.');
264
        $fieldNameParameter = PhpParameter::create('name');
265
        $fieldNameParameter->setType('string');
266
        $methodSetDirty->addParameter($fieldNameParameter);
267
        $fieldStatusParameter = PhpParameter::create('status');
268
        $fieldStatusParameter->setType('bool');
269
        $methodSetDirty->addParameter($fieldStatusParameter);
270
        $methodSetDirty->setBody("\$propertyName = 'dirty'.ucfirst(\$name);\n\$this->\$propertyName = \$status;");
271
        $methodSetDirty->setType('bool');
272
        $class->setMethod($methodSetDirty);
273
274
        $generator = new CodeFileGenerator();
275
        $code = $generator->generate($class);
276
277 View Code Duplication
        if (!file_put_contents(rtrim($targetDirectory, '/').'/'.$className.'.php', $code)) {
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...
278
            throw new ZohoCRMORMException("An error occurred while creating the class $className. Please verify the target directory or the rights of the file.");
279
        }
280
    }
281
282
    /**
283
     * @param  ZCRMPickListValue[] $pickListFieldValues
284
     * @return array
285
     */
286
    public static function ZCRMPickListValueListToArray(array $pickListFieldValues)
287
    {
288
        return array_map(
289
            function (ZCRMPickListValue $pickListValue) {
290
                return [
291
                'displayValue' => $pickListValue->getDisplayValue(),
292
                'sequenceNumber' => $pickListValue->getSequenceNumber(),
293
                'actualValue' => $pickListValue->getActualValue(),
294
                'maps' => $pickListValue->getMaps(),
295
                ];
296
            }, $pickListFieldValues
297
        );
298
    }
299
    /**
300
     * @param  ZCRMField[] $ZCRMfields
301
     * @param  string       $namespace
302
     * @param  string       $className
303
     * @param  string       $daoClassName
304
     * @param  string       $moduleName
305
     * @param  string       $targetDirectory
306
     * @param  string       $moduleSingular
307
     * @param  string       $modulePlural
308
     * @throws ZohoCRMORMException
309
     */
310
    public function generateDao(array $ZCRMfields, $namespace, $className, $daoClassName, $moduleName, $targetDirectory, $moduleSingular, $modulePlural)
311
    {
312
        $class = PhpClass::create();
313
314
        $class->setName($daoClassName)
315
            ->setNamespace($namespace)
316
            ->setParentClassName('\\Wabel\\Zoho\\CRM\\AbstractZohoDao');
317
318
        $fields = [];
319
        foreach ($ZCRMfields as $ZCRMfield) {
320
            $name = $ZCRMfield->getApiName();
321
            $apiName = $ZCRMfield->getApiName();
322
            $type = $ZCRMfield->getDataType();
323
            $system =false;
324
            $lookupModuleName = null;
325
            if(in_array($ZCRMfield->getApiName(), self::$defaultZohoFields)) {
326
                $system = true;
327
            }
328
329
            switch ($type) {
330
            case 'datetime':
331
            case 'date':
332
                $phpType = '\\DateTime';
333
                break;
334
            case 'boolean':
335
                $phpType = 'bool';
336
                break;
337
            case 'bigint':
338
            case 'integer':
339
            case 'autonumber':
340
                $phpType = 'int';
341
                break;
342
            case 'currency':
343
            case 'decimal':
344
            case 'double':
345
            case 'percent':
346
                $phpType = 'float';
347
                break;
348
            case 'multiselectpicklist':
349
                $fields[$name]['values']  = self::ZCRMPickListValueListToArray($ZCRMfield->getPickListFieldValues());
350
                $phpType = 'string[]';
351
                break;
352
            case 'picklist':
353
                $fields[$name]['values']  = self::ZCRMPickListValueListToArray($ZCRMfield->getPickListFieldValues());
354
                $phpType = 'string';
355
                break;
356
            case 'ownerlookup':
357
                $name = self::camelCase($name.'_OwnerID');
358
                $phpType = 'string';
359
                break;
360
            case 'lookup':
361
                $name = self::camelCase($name.'_ID');
362
                $phpType = 'string';
363
                $lookupModuleName = $ZCRMfield->getLookupField() ? $ZCRMfield->getLookupField()->getModule():null;
364
                break;
365
            case 'multiselectlookup':
366
                continue 2;
367
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
368
            case 'userlookup':
369
                $name = self::camelCase($name.'_UserID');
370
                $phpType = 'string';
371
                break;
372
            case 'multiuserlookup':
373
                //@Todo: It's a hypothetical field name based on zoho fields architecture
374
                continue 2;
375
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
376
            case 'fileupload':
377
            case 'consent_lookup':
378
            case 'profileimage':
379
            case 'ALARM':
380
            case 'RRULE':
381
            case 'event_reminder':
382
                //@Todo: We have to see how we can work with it
383
                continue 2;
384
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
385
            default:
386
                $phpType = 'string';
387
                break;
388
            }
389
390
            $fields[$name]['phpType'] = $phpType;
391
            $fields[$name]['getter'] = 'get'.ucfirst(self::camelCase($name));
392
            $fields[$name]['setter'] = 'set'.ucfirst(self::camelCase($name));
393
            $fields[$name]['name'] = self::camelCase($name);
394
            $fields[$name]['apiName'] = $apiName;
395
            $fields[$name]['customfield'] = $ZCRMfield->isCustomField();
396
            $fields[$name]['req'] = $ZCRMfield->isMandatory();
397
            $fields[$name]['type'] = $ZCRMfield->getDataType();
398
            $fields[$name]['isreadonly'] = $ZCRMfield->isReadOnly();
399
            $fields[$name]['maxlength']  = $ZCRMfield->getLength();
400
            $fields[$name]['label']  = $ZCRMfield->getFieldLabel();
401
            $fields[$name]['dv']  = $ZCRMfield->getDefaultValue();
402
            $fields[$name]['system'] = $system;
403
            $fields[$name]['lookupModuleName'] = $lookupModuleName;
404
        }
405
406
        $class->setMethod(PhpMethod::create('getModule')->setBody('return '.var_export($moduleName, true).';'));
407
408
        $class->setMethod(PhpMethod::create('getSingularModuleName')->setBody('return '.var_export($moduleSingular, true).';'));
409
410
        $class->setMethod(PhpMethod::create('getPluralModuleName')->setBody('return '.var_export($modulePlural, true).';'));
411
412
        $class->setMethod(PhpMethod::create('getFieldsDetails')->setBody('return '.var_export($fields, true).';'));
413
414
        $class->setMethod(PhpMethod::create('getBeanClassName')->setBody('return '.var_export($namespace.'\\'.$className, true).';'));
415
416
        $generator = new CodeFileGenerator();
417
        $code = $generator->generate($class);
418
419 View Code Duplication
        if (!file_put_contents(rtrim($targetDirectory, '/').'/'.$daoClassName.'.php', $code)) {
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...
420
            throw new ZohoCRMORMException("An error occurred while creating the DAO $daoClassName. Please verify the target directory exists or the rights of the file.");
421
        }
422
    }
423
424
    private static function camelCase($str, array $noStrip = [])
425
    {
426
        $str = self::upperCamelCase($str, $noStrip);
427
        $str = lcfirst($str);
428
429
        return $str;
430
    }
431
432
    private static function upperCamelCase($str, array $noStrip = [])
433
    {
434
        // non-alpha and non-numeric characters become spaces
435
        $str = preg_replace('/[^a-z0-9'.implode('', $noStrip).']+/i', ' ', $str);
436
        $str = trim($str);
437
        // uppercase the first character of each word
438
        $str = ucwords($str);
439
        $str = str_replace(' ', '', $str);
440
441
        return $str;
442
    }
443
444
    private static function registerProperty(PhpClass $class, $name, $description, $type, $nullable = false)
445
    {
446
        if (!$class->hasProperty($name)) {
447
            $property = PhpProperty::create($name);
448
            $property->setDescription($description);
449
            $property->setType($type);
450
            $property->setVisibility('protected');
451
452
            $class->setProperty($property);
453
        }
454
        
455
456
        $isDirtyName = 'dirty'.ucfirst($name);
457
        if (!$class->hasProperty($isDirtyName) && !in_array($name, self::$defaultORMSystemFields)) {
458
            $dirtyProperty = PhpProperty::create($isDirtyName);
459
            $dirtyProperty->setDescription("Whether '$name' has been changed or not.");
460
            $dirtyProperty->setType('bool');
461
            $dirtyProperty->setVisibility('protected');
462
            $dirtyProperty->setDefaultValue(false);
0 ignored issues
show
Deprecated Code introduced by
The method gossi\codegen\model\part...Part::setDefaultValue() has been deprecated with message: use `setValue()` instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
463
464
            $class->setProperty($dirtyProperty);
465
        }
466
467
        $getterName = 'get'.ucfirst($name);
468
        $getterDescription = 'Get '.lcfirst($description);
469
        $setterName = 'set'.ucfirst($name);
470
        $setterDescription = 'Set '.lcfirst($description);
471
472
        if (!$class->hasMethod($getterName)) {
473
            $method = PhpMethod::create($getterName);
474
            $method->setDescription($getterDescription);
475
            $method->setBody("return \$this->{$name};");
476
            $class->setMethod($method);
477
        }
478
479
        if (!$class->hasMethod($setterName)) {
480
            $method = PhpMethod::create($setterName);
481
            $method->setDescription($setterDescription);
482
            $returnType = $type;
483
            if(strpos($returnType, '[]') !== false) {
484
                $returnType = 'array';
485
            }
486
            $parameter = PhpParameter::create($name)->setType($returnType);
487
            if($returnType === 'array') {
488
                $parameter->setDescription('An array like '.$type);
489
            }
490
            if ($nullable) {
491
                $parameter->setValue(null);
492
            }
493
            $method->addParameter($parameter);
494
            $method->setBody(
495
                "\$this->{$name} = \${$name};\n".
496
                (!in_array($name, self::$defaultORMSystemFields)?'$this->dirty'.ucfirst($name)." = true;\n":"").
497
                'return $this;'
498
            );
499
            $class->setMethod($method);
500
        }
501
    }
502
}
503