Completed
Push — 2.2 ( d12ec2...24c831 )
by
unknown
01:19
created

EntitiesGeneratorService::generateAll()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 8.7377
c 0
b 0
f 0
cc 6
nc 7
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
24
    /**
25
     * @var ZohoClient
26
     */
27
    private $zohoClient;
28
29
    /**
30
     * @var LoggerInterface
31
     */
32
    private $logger;
33
34
    /**
35
     * @var array|string[]
36
     */
37
    private $excludedModules;
38
39
    public static $defaultZohoFields = ['Created_Time', 'Modified_Time', 'Last_Activity_Time',
40
        'Created_By', 'Modified_By', 'Owner'];
41
42
    public static $defaultORMFields = ['createdTime', 'modifiedTime', 'lastActivityTime',
43
        'createdByID', 'modifiedByID', 'createdByName', 'modifiedByName', 'OwnerID', 'OwnerName',
44
        'ZCRMRecord'
45
    ];
46
47
    public static $defaultORMSystemFields = ['createdTime', 'modifiedTime', 'lastActivityTime',
48
        'ZCRMRecord', 'zohoId'
49
    ];
50
51
    public static $defaultDateFields = ['createdTime', 'modifiedTime', 'lastActivityTime'];
52
53
    /**
54
     * EntitiesGeneratorService constructor.
55
     * @param ZohoClient $zohoClient
56
     * @param LoggerInterface $logger
57
     * @param string[] $excludedModules
58
     */
59
    public function __construct(ZohoClient $zohoClient, LoggerInterface $logger, array $excludedModules = [])
60
    {
61
        $this->zohoClient = $zohoClient;
62
        $this->logger = $logger;
63
        $this->excludedModules = $excludedModules;
64
    }
65
66
    /**
67
     * Generate ALL entities for all Zoho modules.
68
     *
69
     * @param string $targetDirectory
70
     * @param string $namespace
71
     *
72
     * @return array Array containing each fully qualified dao class name
73
     */
74
    public function generateAll($targetDirectory, $namespace)
75
    {
76
        /**
77
         * @var $modules ZCRMModule[]
78
         */
79
        $modules = $this->zohoClient->getModules();
80
        $zohoModules = [];
81
        foreach ($modules as $module) {
82
            if (in_array($module->getAPIName(), $this->excludedModules, true)) {
83
                continue;
84
            }
85
            if ($module->isApiSupported()) {
86
                try {
87
                    $module = $this->generateModule(
88
                        $module->getAPIName(), $module->getAPIName(),
89
                        substr($module->getAPIName(), 0, -1), $targetDirectory, $namespace
90
                    );
91
                    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...
92
                        $zohoModules[] = $module;
93
                    }
94
                } catch (ZohoCRMORMException $e) {
95
                    $this->logger->notice(
96
                        'Error thrown when retrieving fields for module {module}. Error message: {error}.',
97
                        [
98
                            '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...
99
                            'error' => $e->getMessage(),
100
                            'exception' => $e,
101
                        ]
102
                    );
103
                }
104
            }
105
        }
106
107
        return $zohoModules;
108
    }
109
110
    /**
111
     * Generate a dao for a zoho module.
112
     *
113
     * @param string $moduleName
114
     * @param string $modulePlural
115
     * @param string $moduleSingular
116
     * @param string $targetDirectory
117
     * @param string $namespace
118
     *
119
     * @return string|null The fully qualified Dao class name
120
     */
121
    public function generateModule($moduleName, $modulePlural, $moduleSingular, $targetDirectory, $namespace)
122
    {
123
        $fieldRecords = $this->zohoClient->getFields($moduleName);
124
125
        if (!$fieldRecords) {
126
            return null;
127
        }
128
        if (!file_exists($targetDirectory)) {
129
            mkdir($targetDirectory, 0775, true);
130
        }
131
132
        $namespace = trim($namespace, '\\');
133
        $className = self::upperCamelCase($moduleSingular);
134
        $daoClassName = $className . 'ZohoDao';
135
136
137
        // Case is a reserved keyword. Let's rename it.
138
        if ($className === 'Case') {
139
            $className = 'ZohoCase';
140
        }
141
142
        $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...
143
        $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...
144
145
        return $namespace . '\\' . $daoClassName;
146
    }
147
148
    /**
149
     * @param ZCRMField[] $ZCRMfields
150
     * @param string $namespace
151
     * @param string $className
152
     * @param string $moduleName
153
     * @param string $targetDirectory
154
     * @param string $moduleSingular
155
     * @throws ZohoCRMORMException
156
     */
157
    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...
158
    {
159
160
        $class = PhpClass::create();
161
        $class->setName($className)
162
            ->setNamespace($namespace)
163
            ->addInterface('\\Wabel\\Zoho\\CRM\\ZohoBeanInterface')
164
            ->setMethod(PhpMethod::create('__construct'));
165
166
        // Let's add the ZohoID property
167
        self::registerProperty($class, 'zohoId', "The ID of this record in Zoho\nType: string\n", 'string');
168
169
        foreach ($ZCRMfields as $ZCRMfield) {
170
            $name = self::camelCase($ZCRMfield->getApiName());
171
            $apiName = $ZCRMfield->getApiName();
172
            $type = $ZCRMfield->getDataType();
173
            $isreadonly = $ZCRMfield->isReadOnly();
174
            $maxlength = $ZCRMfield->getLength();
175
            $label = $ZCRMfield->getFieldLabel();
176
            $customfield = $ZCRMfield->isCustomField();
177
            $nullable = false;
178
179
            $isLookup = false;
180
            $lookupName = null;
181
182
            switch ($type) {
183
                case 'datetime':
184
                case 'date':
185
                    $phpType = '\\DateTimeInterface';
186
                    $nullable = true;
187
                    break;
188
                case 'boolean':
189
                    $phpType = 'bool';
190
                    break;
191
                case 'bigint':
192
                case 'integer':
193
                    $phpType = 'int';
194
                    break;
195
                case 'autonumber':
196
                case 'bigint':
197
                case 'integer':
198
                    $phpType = 'int';
199
                    break;
200
                case 'currency':
201
                case 'decimal':
202
                case 'double':
203
                case 'percent':
204
                    $phpType = 'float';
205
                    break;
206
                case 'multiselectpicklist':
207
                    $phpType = 'string[]';
208
                    $nullable = true;
209
                    break;
210
                case 'picklist':
211
                    $phpType = 'string';
212
                    $nullable = true;
213
                    break;
214 View Code Duplication
                case 'ownerlookup':
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...
215
                    $isLookup = true;
216
                    $lookupName = $name . '_OwnerName';
217
                    $name = $name . '_OwnerID';
218
                    $phpType = 'string';
219
                    break;
220
                case 'lookup':
221
                    $isLookup = true;
222
                    $lookupName = $name . '_Name';
223
                    $name = $name . '_ID';
224
                    $phpType = 'string';
225
                    break;
226
                case 'multiselectlookup':
227
                    continue 2;
228
                    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...
229 View Code Duplication
                case 'userlookup':
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...
230
                    $isLookup = true;
231
                    $lookupName = $name . '_UserName';
232
                    $name = $name . '_UserID';
233
                    $phpType = 'string';
234
                    $nullable = true;
235
                    break;
236
                case 'multiuserlookup':
237
                    //@Todo: It's a hypothetical field name based on zoho fields architecture
238
                    $name = $name . '_UserIDs';
239
                    $phpType = 'string[]';
240
                    $nullable = true;
241
                    break;
242
                case 'fileupload':
243
                    $phpType = 'text';
244
                    break;
245
                case 'consent_lookup':
246
                case 'profileimage':
247
                case 'ALARM':
248
                case 'RRULE':
249
                case 'event_reminder':
250
                    //@Todo: We have to see how we can work with it
251
                    continue 2;
252
                    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...
253
                default:
254
                    $phpType = 'string';
255
                    break;
256
            }
257
            if (in_array($name, self::$defaultDateFields)) {
258
                //Zoho provides these fields by ZCRMRecord::getFieldValue() but also by method in ZCRMRecord
259
                $phpType = '\\DateTimeImmutable';
260
                $nullable = true;
261
            }
262
263
            self::registerProperty(
264
                $class, $name, 'Zoho field ' . $label . "\n" .
265
                'Field API Name: ' . $apiName . "\n" .
266
                'Type: ' . $type . "\n" .
267
                'Read only: ' . ($isreadonly ? 'true' : 'false') . "\n" .
268
                'Max length: ' . $maxlength . "\n" .
269
                'Custom field: ' . ($customfield ? 'true' : 'false') . "\n", $phpType, $nullable
270
            );
271
272
            // For lookup fields, we want to generate both ID and Name fields
273
            if ($isLookup) {
274
                self::registerProperty(
275
                    $class, $lookupName, 'Zoho field ' . $label . " (Name)\n" .
276
                    'Field API Name: ' . $apiName . "\n" .
277
                    'Type: ' . $type . "\n" .
278
                    'Read only: ' . ($isreadonly ? 'true' : 'false') . "\n" .
279
                    'Max length: ' . $maxlength . "\n" .
280
                    'Custom field: ' . ($customfield ? 'true' : 'false') . "\n", $phpType, $nullable
281
                );
282
            }
283
        }
284
285
        /**
286
         * If Zoho provides them we don't have to create them again
287
         */
288
        self::registerProperty($class, 'createdTime', "The time the record was created in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
289
        self::registerProperty($class, 'modifiedTime', "The last time the record was modified in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
290
        self::registerProperty($class, 'lastActivityTime', "The last activity time the record or a related record was modified in Zoho\nType: DateTimeImmutable\n", '\\DateTimeImmutable', true);
291
        self::registerProperty($class, 'createdBy_OwnerID', "The user id who created the entity in Zoho\nType: string\n", 'string');
292
        self::registerProperty($class, 'modifiedBy_OwnerID', "The user id who modified the entity in Zoho\nType: string\n", 'string');
293
        self::registerProperty($class, 'createdBy_OwnerName', "The user id who created the entity in Zoho\nType: string\n", 'string');
294
        self::registerProperty($class, 'modifiedBy_OwnerName', "The user id who modified the entity in Zoho\nType: string\n", 'string');
295
        self::registerProperty($class, 'owner_OwnerID', "Owner ID in Zoho: string\n", 'string');
296
        self::registerProperty($class, 'owner_OwnerName', "Owner Name in Zoho: string\n", 'string');
297
        self::registerProperty($class, 'ZCRMRecord', "The Wrapped Zoho CRM Record\nType: ZCRMRecord\n", '\\zcrmsdk\\crm\\crud\\ZCRMRecord');
298
        $methodIsDirty = PhpMethod::create('isDirty');
299
        $methodIsDirty->setDescription('Returns whether a property is changed or not.');
300
        $methodIsDirty->addParameter(PhpParameter::create('name'));
301
        $methodIsDirty->setBody("\$propertyName = 'dirty'.ucfirst(\$name);\nreturn \$this->\$propertyName;");
302
        $methodIsDirty->setType('bool');
303
        $class->setMethod($methodIsDirty);
304
        $methodSetDirty = PhpMethod::create('setDirty');
305
        $methodSetDirty->setDescription('Returns whether a property is changed or not.');
306
        $fieldNameParameter = PhpParameter::create('name');
307
        $fieldNameParameter->setType('string');
308
        $methodSetDirty->addParameter($fieldNameParameter);
309
        $fieldStatusParameter = PhpParameter::create('status');
310
        $fieldStatusParameter->setType('bool');
311
        $methodSetDirty->addParameter($fieldStatusParameter);
312
        $methodSetDirty->setBody("\$propertyName = 'dirty'.ucfirst(\$name);\n\$this->\$propertyName = \$status;");
313
        $methodSetDirty->setType('bool');
314
        $class->setMethod($methodSetDirty);
315
316
        $generator = new CodeFileGenerator();
317
        $code = $generator->generate($class);
318
319 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...
320
            throw new ZohoCRMORMException("An error occurred while creating the class $className. Please verify the target directory or the rights of the file.");
321
        }
322
    }
323
324
    /**
325
     * @param ZCRMPickListValue[] $pickListFieldValues
326
     * @return array
327
     */
328
    public static function ZCRMPickListValueListToArray(array $pickListFieldValues)
329
    {
330
        return array_map(
331
            function (ZCRMPickListValue $pickListValue) {
332
                return [
333
                    'displayValue' => $pickListValue->getDisplayValue(),
334
                    'sequenceNumber' => $pickListValue->getSequenceNumber(),
335
                    'actualValue' => $pickListValue->getActualValue(),
336
                    'maps' => $pickListValue->getMaps(),
337
                ];
338
            }, $pickListFieldValues
339
        );
340
    }
341
342
    /**
343
     * @param ZCRMField[] $ZCRMfields
344
     * @param string $namespace
345
     * @param string $className
346
     * @param string $daoClassName
347
     * @param string $moduleName
348
     * @param string $targetDirectory
349
     * @param string $moduleSingular
350
     * @param string $modulePlural
351
     * @throws ZohoCRMORMException
352
     */
353
    public function generateDao(array $ZCRMfields, $namespace, $className, $daoClassName, $moduleName, $targetDirectory, $moduleSingular, $modulePlural)
354
    {
355
        $class = PhpClass::create();
356
357
        $class->setName($daoClassName)
358
            ->setNamespace($namespace)
359
            ->setParentClassName('\\Wabel\\Zoho\\CRM\\AbstractZohoDao');
360
361
        $fields = [];
362
        foreach ($ZCRMfields as $ZCRMfield) {
363
            $name = $ZCRMfield->getApiName();
364
            $apiName = $ZCRMfield->getApiName();
365
            $type = $ZCRMfield->getDataType();
366
            $system = false;
367
            $lookupModuleName = null;
368
            if (in_array($ZCRMfield->getApiName(), self::$defaultZohoFields)) {
369
                $system = true;
370
            }
371
372
            $isLookup = false;
373
            $lookupName = null;
374
375
            switch ($type) {
376
                case 'datetime':
377
                case 'date':
378
                    $phpType = '\\DateTime';
379
                    break;
380
                case 'boolean':
381
                    $phpType = 'bool';
382
                    break;
383
                case 'bigint':
384
                case 'integer':
385
                    $phpType = 'int';
386
                    break;
387
                case 'autonumber':
388
                case 'bigint':
389
                case 'integer':
390
                    $phpType = 'int';
391
                    break;
392
                case 'currency':
393
                case 'decimal':
394
                case 'double':
395
                case 'percent':
396
                    $phpType = 'float';
397
                    break;
398
                case 'multiselectpicklist':
399
                    $fields[$name]['values'] = self::ZCRMPickListValueListToArray($ZCRMfield->getPickListFieldValues());
400
                    $phpType = 'string[]';
401
                    break;
402
                case 'picklist':
403
                    $fields[$name]['values'] = self::ZCRMPickListValueListToArray($ZCRMfield->getPickListFieldValues());
404
                    $phpType = 'string';
405
                    break;
406 View Code Duplication
                case 'ownerlookup':
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...
407
                    $isLookup = true;
408
                    $lookupName = $name . '_OwnerName';
409
                    $name = $name . '_OwnerID';
410
                    $phpType = 'string';
411
                    break;
412
                case 'lookup':
413
                    $isLookup = true;
414
                    $lookupName = $name . '_Name';
415
                    $name = $name . '_ID';
416
                    $phpType = 'string';
417
                    $lookupModuleName = $ZCRMfield->getLookupField() ? $ZCRMfield->getLookupField()->getModule() : null;
418
                    break;
419
                case 'multiselectlookup':
420
                    continue 2;
421
                    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...
422 View Code Duplication
                case 'userlookup':
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...
423
                    $isLookup = true;
424
                    $lookupName = $name . '_UserName';
425
                    $name = $name . '_UserID';
426
                    $phpType = 'string';
427
                    break;
428
                case 'multiuserlookup':
429
                    //@Todo: It's a hypothetical field name based on zoho fields architecture
430
                    continue 2;
431
                    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...
432
                case 'fileupload':
433
                case 'consent_lookup':
434
                case 'profileimage':
435
                case 'ALARM':
436
                case 'RRULE':
437
                case 'event_reminder':
438
                    //@Todo: We have to see how we can work with it
439
                    continue 2;
440
                    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...
441
                default:
442
                    $phpType = 'string';
443
                    break;
444
            }
445
446
            $fields[$name]['phpType'] = $phpType;
447
            $fields[$name]['getter'] = 'get' . ucfirst(self::camelCase($name));
448
            $fields[$name]['setter'] = 'set' . ucfirst(self::camelCase($name));
449
            $fields[$name]['name'] = $name;
450
            $fields[$name]['apiName'] = $apiName;
451
            $fields[$name]['customfield'] = $ZCRMfield->isCustomField();
452
            $fields[$name]['req'] = $ZCRMfield->isMandatory();
453
            $fields[$name]['type'] = $ZCRMfield->getDataType();
454
            $fields[$name]['isreadonly'] = $ZCRMfield->isReadOnly();
455
            $fields[$name]['maxlength'] = $ZCRMfield->getLength();
456
            $fields[$name]['label'] = $ZCRMfield->getFieldLabel();
457
            $fields[$name]['dv'] = $ZCRMfield->getDefaultValue();
458
            $fields[$name]['system'] = $system;
459
            $fields[$name]['lookupModuleName'] = $lookupModuleName;
460
461
            // For lookup fields, we want to generate both ID and Name fields
462
            if ($isLookup) {
463
                $name = $lookupName;
464
                $fields[$name]['phpType'] = $phpType;
465
                $fields[$name]['getter'] = 'get' . ucfirst(self::camelCase($name));
466
                $fields[$name]['setter'] = 'set' . ucfirst(self::camelCase($name));
467
                $fields[$name]['name'] = $name;
468
                $fields[$name]['apiName'] = $apiName;
469
                $fields[$name]['customfield'] = $ZCRMfield->isCustomField();
470
                $fields[$name]['req'] = $ZCRMfield->isMandatory();
471
                $fields[$name]['type'] = $ZCRMfield->getDataType();
472
                $fields[$name]['isreadonly'] = $ZCRMfield->isReadOnly();
473
                $fields[$name]['maxlength'] = $ZCRMfield->getLength();
474
                $fields[$name]['label'] = $ZCRMfield->getFieldLabel();
475
                $fields[$name]['dv'] = $ZCRMfield->getDefaultValue();
476
                $fields[$name]['system'] = $system;
477
                $fields[$name]['lookupModuleName'] = $lookupModuleName;
478
            }
479
        }
480
481
        $class->setMethod(PhpMethod::create('getModule')->setBody('return ' . var_export($moduleName, true) . ';'));
482
483
        $class->setMethod(PhpMethod::create('getSingularModuleName')->setBody('return ' . var_export($moduleSingular, true) . ';'));
484
485
        $class->setMethod(PhpMethod::create('getPluralModuleName')->setBody('return ' . var_export($modulePlural, true) . ';'));
486
487
        $class->setMethod(PhpMethod::create('getFieldsDetails')->setBody('return ' . var_export($fields, true) . ';'));
488
489
        $class->setMethod(PhpMethod::create('getBeanClassName')->setBody('return ' . var_export($namespace . '\\' . $className, true) . ';'));
490
491
        $generator = new CodeFileGenerator();
492
        $code = $generator->generate($class);
493
494 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...
495
            throw new ZohoCRMORMException("An error occurred while creating the DAO $daoClassName. Please verify the target directory exists or the rights of the file.");
496
        }
497
    }
498
499
    private static function camelCase($str, array $noStrip = [])
500
    {
501
        $str = self::upperCamelCase($str, $noStrip);
502
        $str = lcfirst($str);
503
504
        return $str;
505
    }
506
507
    private static function upperCamelCase($str, array $noStrip = [])
508
    {
509
        // non-alpha and non-numeric characters become spaces
510
        $str = preg_replace('/[^a-z0-9' . implode('', $noStrip) . ']+/i', ' ', $str);
511
        $str = trim($str);
512
        // uppercase the first character of each word
513
        $str = ucwords($str);
514
        $str = str_replace(' ', '', $str);
515
516
        return $str;
517
    }
518
519
    private static function registerProperty(PhpClass $class, $name, $description, $type, $nullable = false)
520
    {
521
        if (!$class->hasProperty($name)) {
522
            $property = PhpProperty::create($name);
523
            $property->setDescription($description);
524
            $property->setType($type);
525
            $property->setVisibility('protected');
526
527
            $class->setProperty($property);
528
        }
529
530
531
        $isDirtyName = 'dirty' . ucfirst($name);
532
        if (!$class->hasProperty($isDirtyName) && !in_array($name, self::$defaultORMSystemFields)) {
533
            $dirtyProperty = PhpProperty::create($isDirtyName);
534
            $dirtyProperty->setDescription("Whether '$name' has been changed or not.");
535
            $dirtyProperty->setType('bool');
536
            $dirtyProperty->setVisibility('protected');
537
            $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...
538
539
            $class->setProperty($dirtyProperty);
540
        }
541
542
        $getterName = 'get' . ucfirst($name);
543
        $getterDescription = 'Get ' . lcfirst($description);
544
        $setterName = 'set' . ucfirst($name);
545
        $setterDescription = 'Set ' . lcfirst($description);
546
547
        if (!$class->hasMethod($getterName)) {
548
            $method = PhpMethod::create($getterName);
549
            $method->setDescription($getterDescription);
550
            $method->setBody("return \$this->{$name};");
551
            $class->setMethod($method);
552
        }
553
554
        if (!$class->hasMethod($setterName)) {
555
            $method = PhpMethod::create($setterName);
556
            $method->setDescription($setterDescription);
557
            $returnType = $type;
558
            if (strpos($returnType, '[]') !== false) {
559
                $returnType = 'array';
560
            }
561
            $parameter = PhpParameter::create($name)->setType($returnType);
562
            if ($returnType === 'array') {
563
                $parameter->setDescription('An array like ' . $type);
564
            }
565
            if ($nullable) {
566
                $parameter->setValue(null);
567
            }
568
            $method->addParameter($parameter);
569
            $method->setBody(
570
                "\$this->{$name} = \${$name};\n" .
571
                (!in_array($name, self::$defaultORMSystemFields) ? '$this->dirty' . ucfirst($name) . " = true;\n" : "") .
572
                'return $this;'
573
            );
574
            $class->setMethod($method);
575
        }
576
    }
577
}
578