Completed
Pull Request — 2.0 (#37)
by Raphaël
10:32
created

ZCRMPickListValueListToArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
nc 1
cc 1
nop 1
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
14
/**
15
 * This class is in charge of generating Zoho entities.
16
 */
17
class EntitiesGeneratorService
18
{
19
    private $zohoClient;
20
    private $logger;
21
22
    public static $defaultZohoFields = ['Created_Time','Modified_Time', 'Last_Activity_Time',
23
        'Created_By', 'Modified_By', 'Owner'];
24
25
    public static $defaultORMFields = ['createdTime','modifiedTime', 'lastActivityTime',
26
        'createdByID', 'modifiedByID', 'createdByName', 'modifiedByName', 'OwnerID', 'OwnerName',
27
        'ZCRMRecord'
28
    ];
29
30
    public static $defaultORMSystemFields = ['createdTime','modifiedTime', 'lastActivityTime',
31
        'ZCRMRecord', 'zohoId'
32
    ];
33
34
    public static $defaultDateFields = ['createdTime','modifiedTime', 'lastActivityTime'];
35
36
    public function __construct(ZohoClient $zohoClient, LoggerInterface $logger)
37
    {
38
        $this->zohoClient = $zohoClient;
39
        $this->logger = $logger;
40
    }
41
42
    /**
43
     * Generate ALL entities for all Zoho modules.
44
     *
45
     * @param string $targetDirectory
46
     * @param string $namespace
47
     *
48
     * @return array Array containing each fully qualified dao class name
49
     */
50
    public function generateAll($targetDirectory, $namespace)
51
    {
52
        /**
53
         * @var $modules \ZCRMModule[]
54
         */
55
        $modules = $this->zohoClient->getModules();
56
        $zohoModules = [];
57
        foreach ($modules as $module) {
58
            if($module->isApiSupported()){
59
                try {
60
                    $module = $this->generateModule($module->getAPIName(), $module->getPluralLabel(),
61
                        $module->getSingularLabel(), $targetDirectory, $namespace);
62
                    if($module){
0 ignored issues
show
Bug Best Practice introduced by
The expression $module of type null|string 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...
63
                        $zohoModules[] = $module;
64
                    }
65
                } catch (ZohoCRMORMException $e) {
66
                    $this->logger->notice('Error thrown when retrieving fields for module {module}. Error message: {error}.',
67
                        [
68
                            'module' => $module->getAPIName(),
0 ignored issues
show
Bug introduced by
The method getAPIName cannot be called on $module (of type null|string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
69
                            'error' => $e->getMessage(),
70
                            'exception' => $e,
71
                        ]);
72
                }
73
            }
74
        }
75
76
        return $zohoModules;
77
    }
78
79
    /**
80
     * Generate a dao for a zoho module.
81
     *
82
     * @param string $moduleName
83
     * @param string $modulePlural
84
     * @param string $moduleSingular
85
     * @param string $targetDirectory
86
     * @param string $namespace
87
     *
88
     * @return string|null The fully qualified Dao class name
89
     */
90
    public function generateModule($moduleName, $modulePlural, $moduleSingular, $targetDirectory, $namespace)
91
    {
92
        $fieldRecords = $this->zohoClient->getFields($moduleName);
93
94
        if(!$fieldRecords){
95
            return null;
96
        }
97
        if (!file_exists($targetDirectory)) {
98
            mkdir($targetDirectory, 0775, true);
99
        }
100
101
        $namespace = trim($namespace, '\\');
102
        $className = self::upperCamelCase($moduleSingular);
103
        $daoClassName = $className.'ZohoDao';
104
105
106
        // Case is a reserved keyword. Let's rename it.
107
        if ($className === 'Case') {
108
            $className = 'ZohoCase';
109
        }
110
111
        $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<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...
112
        $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<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...
113
114
        return $namespace.'\\'.$daoClassName;
115
    }
116
117
    /**
118
     * @param \ZCRMField[] $ZCRMfields
119
     * @param string $namespace
120
     * @param string $className
121
     * @param string $moduleName
122
     * @param string $targetDirectory
123
     * @param string $moduleSingular
124
     * @throws ZohoCRMORMException
125
     */
126
    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...
127
    {
128
129
        $class = PhpClass::create();
130
        $class->setName($className)
131
            ->setNamespace($namespace)
132
            ->addInterface('\\Wabel\\Zoho\\CRM\\ZohoBeanInterface')
133
            ->setMethod(PhpMethod::create('__construct'));
134
135
        // Let's add the ZohoID property
136
        self::registerProperty($class, 'zohoId', "The ID of this record in Zoho\nType: string\n", 'string');
137
138
        foreach ($ZCRMfields as $ZCRMfield) {
139
            $name = self::camelCase($ZCRMfield->getApiName());
140
            $apiName = $ZCRMfield->getApiName();
141
            $type = $ZCRMfield->getDataType();
142
            $isreadonly = $ZCRMfield->isReadOnly();
143
            $maxlength = $ZCRMfield->getLength();
144
            $label = $ZCRMfield->getFieldLabel();
145
            $customfield = $ZCRMfield->isCustomField();
146
            $nullable = false;
147
            switch ($type) {
148
                case 'datetime':
149
                case 'date':
150
                    $phpType = '\\DateTimeInterface';
151
                    $nullable = true;
152
                    break;
153
                case 'boolean':
154
                    $phpType = 'bool';
155
                    break;
156
                case 'bigint':
157
                case 'integer':
158
                    $phpType = 'int';
159
                    break;
160
                case 'autonumber':
161
                case 'bigint':
162
                case 'integer':
163
                    $phpType = 'int';
164
                    break;
165
                case 'currency':
166
                case 'decimal':
167
                case 'double':
168
                case 'percent':
169
                    $phpType = 'float';
170
                    break;
171
                case 'multiselectpicklist':
172
                    $phpType = 'string[]';
173
                    $nullable = true;
174
                    break;
175
                case 'picklist':
176
                    $phpType = 'string';
177
                    $nullable = true;
178
                    break;
179
                case 'ownerlookup':
180
                    $name = self::camelCase($name.'_OwnerID');
181
                    $phpType = 'string';
182
                    break;
183
                case 'lookup':
184
                    $name = self::camelCase($name.'_ID');
185
                    $phpType = 'string';
186
                    break;
187
                case 'multiselectlookup':
188
                    continue 2;
189
                    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...
190
                case 'userlookup':
191
                    $name = self::camelCase($name.'_UserID');
192
                    $phpType = 'string';
193
                    $nullable = true;
194
                    break;
195
                case 'multiuserlookup':
196
                    //@Todo: It's a hypothetical field name based on zoho fields architecture
197
                    $name = self::camelCase($name.'_UserIDs');
198
                    $phpType = 'string[]';
199
                    $nullable = true;
200
                    break;
201
                case 'fileupload':
202
                    $phpType = 'text';
203
                    break;
204
                case 'consent_lookup':
205
                case 'profileimage':
206
                case 'ALARM':
207
                case 'RRULE':
208
                case 'event_reminder':
209
                    //@Todo: We have to see how we can work with it
210
                    continue 2;
211
                    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...
212
                default:
213
                    $phpType = 'string';
214
                    break;
215
            }
216
            if(in_array($name, self::$defaultDateFields)){
217
                //Zoho provides these fields by ZCRMRecord::getFieldValue() but also by method in ZCRMRecord
218
                $phpType = '\\DateTimeImmutable';
219
                $nullable = true;
220
            }
221
222
            self::registerProperty($class, $name, 'Zoho field '.$label."\n".
223
                'Field API Name: '.$apiName."\n".
224
                'Type: '.$type."\n".
225
                'Read only: '.($isreadonly ? 'true' : 'false')."\n".
226
                'Max length: '.$maxlength."\n".
227
                'Custom field: '.($customfield ? 'true' : 'false')."\n", $phpType, $nullable);
228
        }
229
230
        /**
231
         * If Zoho provides them we don't have to create them again
232
         */
233
        self::registerProperty($class, 'createdTime', "The time the record was created in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
234
        self::registerProperty($class, 'modifiedTime', "The last time the record was modified in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
235
        self::registerProperty($class, 'lastActivityTime', "The last activity time the record or a related record was modified in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
236
        self::registerProperty($class, 'createdByOwnerID', "The user id who created the entity in Zoho\nType: string\n", 'string');
237
        self::registerProperty($class, 'modifiedByOwnerID', "The user id who modified the entity in Zoho\nType: string\n", 'string');
238
        self::registerProperty($class, 'createdByOwnerName', "The user id who created the entity in Zoho\nType: string\n", 'string');
239
        self::registerProperty($class, 'modifiedByOwnerName', "The user id who modified the entity in Zoho\nType: string\n", 'string');
240
        self::registerProperty($class, 'ownerOwnerID', "Owner ID in Zoho: string\n", 'string');
241
        self::registerProperty($class, 'ownerOwnerName', "Owner Name in Zoho: string\n", 'string');
242
        self::registerProperty($class, 'ZCRMRecord', "The Wrapped Zoho CRM Record\nType: ZCRMRecord\n", '\\ZCRMRecord');
243
        $methodIsDirty = PhpMethod::create('isDirty');
244
        $methodIsDirty->setDescription('Returns whether a property is changed or not.');
245
        $methodIsDirty->addParameter(PhpParameter::create('name'));
246
        $methodIsDirty->setBody("\$propertyName = 'dirty'.ucfirst(\$name);\nreturn \$this->\$propertyName;");
247
        $methodIsDirty->setType('bool');
248
        $class->setMethod($methodIsDirty);
249
        $methodSetDirty = PhpMethod::create('setDirty');
250
        $methodSetDirty->setDescription('Returns whether a property is changed or not.');
251
        $fieldNameParameter = PhpParameter::create('name');
252
        $fieldNameParameter->setType('string');
253
        $methodSetDirty->addParameter($fieldNameParameter);
254
        $fieldStatusParameter = PhpParameter::create('status');
255
        $fieldStatusParameter->setType('bool');
256
        $methodSetDirty->addParameter($fieldStatusParameter);
257
        $methodSetDirty->setBody("\$propertyName = 'dirty'.ucfirst(\$name);\n\$this->\$propertyName = \$status;");
258
        $methodSetDirty->setType('bool');
259
        $class->setMethod($methodSetDirty);
260
261
        $generator = new CodeFileGenerator();
262
        $code = $generator->generate($class);
263
264 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...
265
            throw new ZohoCRMORMException("An error occurred while creating the class $className. Please verify the target directory or the rights of the file.");
266
        }
267
    }
268
269
    /**
270
     * @param \ZCRMPickListValue[] $pickListFieldValues
271
     * @return array
272
     */
273
    public static function ZCRMPickListValueListToArray(array $pickListFieldValues){
274
        return array_map(function (\ZCRMPickListValue $pickListValue){
275
            return [
276
                'displayValue' => $pickListValue->getDisplayValue(),
277
                'sequenceNumber' => $pickListValue->getSequenceNumber(),
278
                'actualValue' => $pickListValue->getActualValue(),
279
                'maps' => $pickListValue->getMaps(),
280
            ];
281
        },$pickListFieldValues);
282
    }
283
    /**
284
     * @param \ZCRMField[] $ZCRMfields
285
     * @param string $namespace
286
     * @param string $className
287
     * @param string $daoClassName
288
     * @param string $moduleName
289
     * @param string $targetDirectory
290
     * @param string $moduleSingular
291
     * @param string $modulePlural
292
     * @throws ZohoCRMORMException
293
     */
294
    public function generateDao(array $ZCRMfields, $namespace, $className, $daoClassName, $moduleName, $targetDirectory, $moduleSingular, $modulePlural)
295
    {
296
        $class = PhpClass::create();
297
298
        $class->setName($daoClassName)
299
            ->setNamespace($namespace)
300
            ->setParentClassName('\\Wabel\\Zoho\\CRM\\AbstractZohoDao');
301
302
        $fields = [];
303
        foreach ($ZCRMfields as $ZCRMfield) {
304
            $name = $ZCRMfield->getApiName();
305
            $apiName = $ZCRMfield->getApiName();
306
            $type = $ZCRMfield->getDataType();
307
            $system =false;
308
            $lookupModuleName = null;
309
            if(in_array($ZCRMfield->getApiName(), self::$defaultZohoFields)){
310
                $system = true;
311
            }
312
313
            switch ($type) {
314
                case 'datetime':
315
                case 'date':
316
                    $phpType = '\\DateTime';
317
                    break;
318
                case 'boolean':
319
                    $phpType = 'bool';
320
                    break;
321
                case 'bigint':
322
                case 'integer':
323
                    $phpType = 'int';
324
                    break;
325
                case 'autonumber':
326
                case 'bigint':
327
                case 'integer':
328
                    $phpType = 'int';
329
                    break;
330
                case 'currency':
331
                case 'decimal':
332
                case 'double':
333
                case 'percent':
334
                    $phpType = 'float';
335
                    break;
336
                case 'multiselectpicklist':
337
                    $fields[$name]['values']  = self::ZCRMPickListValueListToArray($ZCRMfield->getPickListFieldValues());
338
                    $phpType = 'string[]';
339
                    break;
340
                case 'picklist':
341
                    $fields[$name]['values']  = self::ZCRMPickListValueListToArray($ZCRMfield->getPickListFieldValues());
342
                    $phpType = 'string';
343
                    break;
344
                case 'ownerlookup':
345
                    $name = self::camelCase($name.'_OwnerID');
346
                    $phpType = 'string';
347
                    break;
348
                case 'lookup':
349
                    $name = self::camelCase($name.'_ID');
350
                    $phpType = 'string';
351
                    $lookupModuleName = $ZCRMfield->getLookupField() ? $ZCRMfield->getLookupField()->getModule():null;
352
                    break;
353
                case 'multiselectlookup':
354
                    continue 2;
355
                    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...
356
                case 'userlookup':
357
                    $name = self::camelCase($name.'_UserID');
358
                    $phpType = 'string';
359
                    break;
360
                case 'multiuserlookup':
361
                    //@Todo: It's a hypothetical field name based on zoho fields architecture
362
                    continue 2;
363
                    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...
364
                case 'fileupload':
365
                case 'consent_lookup':
366
                case 'profileimage':
367
                case 'ALARM':
368
                case 'RRULE':
369
                case 'event_reminder':
370
                    //@Todo: We have to see how we can work with it
371
                    continue 2;
372
                    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...
373
                default:
374
                    $phpType = 'string';
375
                    break;
376
            }
377
378
            $fields[$name]['phpType'] = $phpType;
379
            $fields[$name]['getter'] = 'get'.ucfirst(self::camelCase($name));
380
            $fields[$name]['setter'] = 'set'.ucfirst(self::camelCase($name));
381
            $fields[$name]['name'] = self::camelCase($name);
382
            $fields[$name]['apiName'] = $apiName;
383
            $fields[$name]['customfield'] = $ZCRMfield->isCustomField();
384
            $fields[$name]['req'] = $ZCRMfield->isMandatory();
385
            $fields[$name]['type'] = $ZCRMfield->getDataType();
386
            $fields[$name]['isreadonly'] = $ZCRMfield->isReadOnly();
387
            $fields[$name]['maxlength']  = $ZCRMfield->getLength();
388
            $fields[$name]['label']  = $ZCRMfield->getFieldLabel();
389
            $fields[$name]['dv']  = $ZCRMfield->getDefaultValue();
390
            $fields[$name]['system'] = $system;
391
            $fields[$name]['lookupModuleName'] = $lookupModuleName;
392
        }
393
394
        $class->setMethod(PhpMethod::create('getModule')->setBody('return '.var_export($moduleName, true).';'));
395
396
        $class->setMethod(PhpMethod::create('getSingularModuleName')->setBody('return '.var_export($moduleSingular, true).';'));
397
398
        $class->setMethod(PhpMethod::create('getPluralModuleName')->setBody('return '.var_export($modulePlural, true).';'));
399
400
        $class->setMethod(PhpMethod::create('getFieldsDetails')->setBody('return '.var_export($fields, true).';'));
401
402
        $class->setMethod(PhpMethod::create('getBeanClassName')->setBody('return '.var_export($namespace.'\\'.$className, true).';'));
403
404
        $generator = new CodeFileGenerator();
405
        $code = $generator->generate($class);
406
407 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...
408
            throw new ZohoCRMORMException("An error occurred while creating the DAO $daoClassName. Please verify the target directory exists or the rights of the file.");
409
        }
410
    }
411
412
    private static function camelCase($str, array $noStrip = [])
413
    {
414
        $str = self::upperCamelCase($str, $noStrip);
415
        $str = lcfirst($str);
416
417
        return $str;
418
    }
419
420
    private static function upperCamelCase($str, array $noStrip = [])
421
    {
422
        // non-alpha and non-numeric characters become spaces
423
        $str = preg_replace('/[^a-z0-9'.implode('', $noStrip).']+/i', ' ', $str);
424
        $str = trim($str);
425
        // uppercase the first character of each word
426
        $str = ucwords($str);
427
        $str = str_replace(' ', '', $str);
428
429
        return $str;
430
    }
431
432
    private static function registerProperty(PhpClass $class, $name, $description, $type, $nullable = false)
433
    {
434
        if (!$class->hasProperty($name)) {
435
            $property = PhpProperty::create($name);
436
            $property->setDescription($description);
437
            $property->setType($type);
438
            $property->setVisibility('protected');
439
440
            $class->setProperty($property);
441
        }
442
        
443
444
        $isDirtyName = 'dirty'.ucfirst($name);
445
        if (!$class->hasProperty($isDirtyName) && !in_array($name,self::$defaultORMSystemFields)) {
446
            $dirtyProperty = PhpProperty::create($isDirtyName);
447
            $dirtyProperty->setDescription("Whether '$name' has been changed or not.");
448
            $dirtyProperty->setType('bool');
449
            $dirtyProperty->setVisibility('protected');
450
            $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...
451
452
            $class->setProperty($dirtyProperty);
453
        }
454
455
        $getterName = 'get'.ucfirst($name);
456
        $getterDescription = 'Get '.lcfirst($description);
457
        $setterName = 'set'.ucfirst($name);
458
        $setterDescription = 'Set '.lcfirst($description);
459
460
        if (!$class->hasMethod($getterName)) {
461
            $method = PhpMethod::create($getterName);
462
            $method->setDescription($getterDescription);
463
            $method->setBody("return \$this->{$name};");
464
            $class->setMethod($method);
465
        }
466
467
        if (!$class->hasMethod($setterName)) {
468
            $method = PhpMethod::create($setterName);
469
            $method->setDescription($setterDescription);
470
            $returnType = $type;
471
            if(strpos($returnType,'[]') !== false){
472
                $returnType = 'array';
473
            }
474
            $parameter = PhpParameter::create($name)->setType($returnType);
475
            if($returnType === 'array'){
476
                $parameter->setDescription('An array like '.$type);
477
            }
478
            if ($nullable) {
479
                $parameter->setValue(null);
480
            }
481
            $method->addParameter($parameter);
482
            $method->setBody("\$this->{$name} = \${$name};\n".
483
                (!in_array($name,self::$defaultORMSystemFields)?'$this->dirty'.ucfirst($name)." = true;\n":"").
484
                             'return $this;');
485
            $class->setMethod($method);
486
        }
487
    }
488
}
489