Completed
Push — master ( 50f72a...47e8e3 )
by Vitaly
02:53
created

Generator   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 614
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 49
Bugs 9 Features 25
Metric Value
wmc 37
c 49
b 9
f 25
lcom 1
cbo 6
dl 0
loc 614
rs 8.6

20 Methods

Rating   Name   Duplication   Size   Complexity  
A transliterated() 0 51 1
A constantNameByValue() 0 13 2
A entityName() 0 4 1
A getValidName() 0 4 1
A fullEntityName() 0 4 1
A fieldName() 0 4 1
A additionalFieldType() 0 4 1
A generateFieldConditionMethod() 0 14 1
A generateLocalizedFieldConditionMethod() 0 14 1
A generateTableFieldMethod() 0 12 1
B createTableRowClass() 0 30 2
A createTableClass() 0 48 2
B createEntityClass() 0 42 3
B createQueryClass() 0 39 2
A entityHash() 0 9 1
A entityParent() 0 13 2
A entityNavigations() 0 8 1
A navigationFields() 0 12 3
D createEntityClasses() 0 129 9
A __construct() 0 5 1
1
<?php
2
//[PHPCOMPRESSOR(remove,start)]
3
/**
4
 * Created by PhpStorm.
5
 * User: VITALYIEGOROV
6
 * Date: 09.12.15
7
 * Time: 14:34
8
 */
9
namespace samsoncms\api;
10
11
use samson\activerecord\dbMySQLConnector;
12
use samsoncms\api\generator\exception\ParentEntityNotFound;
13
use samsoncms\api\generator\Metadata;
14
use samsoncms\api\query\Generic;
15
use samsonframework\orm\ArgumentInterface;
16
use samsonframework\orm\DatabaseInterface;
17
18
/**
19
 * Entity classes generator.
20
 * @package samsoncms\api
21
 */
22
class Generator
23
{
24
    /** @var DatabaseInterface */
25
    protected $database;
26
27
    /** @var \samsonphp\generator\Generator */
28
    protected $generator;
29
30
    /** @var Metadata[] Collection of entities metadata */
31
    protected $metadata;
32
33
    /**
34
     * Transliterate string to english.
35
     *
36
     * @param string $string Source string
37
     * @return string Transliterated string
38
     */
39
    protected function transliterated($string)
40
    {
41
        return str_replace(
42
            ' ',
43
            '',
44
            ucwords(iconv("UTF-8", "UTF-8//IGNORE", strtr($string, array(
45
                            "'" => "",
46
                            "`" => "",
47
                            "-" => " ",
48
                            "_" => " ",
49
                            "а" => "a", "А" => "a",
50
                            "б" => "b", "Б" => "b",
51
                            "в" => "v", "В" => "v",
52
                            "г" => "g", "Г" => "g",
53
                            "д" => "d", "Д" => "d",
54
                            "е" => "e", "Е" => "e",
55
                            "ж" => "zh", "Ж" => "zh",
56
                            "з" => "z", "З" => "z",
57
                            "и" => "i", "И" => "i",
58
                            "й" => "y", "Й" => "y",
59
                            "к" => "k", "К" => "k",
60
                            "л" => "l", "Л" => "l",
61
                            "м" => "m", "М" => "m",
62
                            "н" => "n", "Н" => "n",
63
                            "о" => "o", "О" => "o",
64
                            "п" => "p", "П" => "p",
65
                            "р" => "r", "Р" => "r",
66
                            "с" => "s", "С" => "s",
67
                            "т" => "t", "Т" => "t",
68
                            "у" => "u", "У" => "u",
69
                            "ф" => "f", "Ф" => "f",
70
                            "х" => "h", "Х" => "h",
71
                            "ц" => "c", "Ц" => "c",
72
                            "ч" => "ch", "Ч" => "ch",
73
                            "ш" => "sh", "Ш" => "sh",
74
                            "щ" => "sch", "Щ" => "sch",
75
                            "ъ" => "", "Ъ" => "",
76
                            "ы" => "y", "Ы" => "y",
77
                            "ь" => "", "Ь" => "",
78
                            "э" => "e", "Э" => "e",
79
                            "ю" => "yu", "Ю" => "yu",
80
                            "я" => "ya", "Я" => "ya",
81
                            "і" => "i", "І" => "i",
82
                            "ї" => "yi", "Ї" => "yi",
83
                            "є" => "e", "Є" => "e"
84
                        )
85
                    )
86
                )
87
            )
88
        );
89
    }
90
91
    /**
92
     * Get class constant name by its value.
93
     *
94
     * @param string $value Constant value
95
     * @param string $className Class name
96
     * @return string Full constant name
97
     */
98
    protected function constantNameByValue($value, $className = Field::ENTITY)
99
    {
100
        // Get array where class constants are values and their values are keys
101
        $nameByValue = array_flip((new \ReflectionClass($className))->getConstants());
102
103
        // Try to find constant by its value
104
        if (null !== $nameByValue[$value]) {
105
            // Return constant name
106
            return $nameByValue[$value];
107
        }
108
109
        return '';
110
    }
111
112
    /**
113
     * Get correct entity name.
114
     *
115
     * @param string $navigationName Original navigation entity name
116
     * @return string Correct PHP-supported entity name
117
     */
118
    protected function entityName($navigationName)
119
    {
120
        return ucfirst($this->getValidName($this->transliterated($navigationName)));
121
    }
122
	
123
    /**
124
     * Remove all wrong characters from entity name
125
     *
126
     * @param string $navigationName Original navigation entity name
127
     * @return string Correct PHP-supported entity name
128
     */
129
    protected function getValidName($navigationName)
130
    {
131
        return preg_replace('/(^\d*)|([^\w\d_])/', '', $navigationName);
132
    }
133
134
    /**
135
     * Get correct full entity name with name space.
136
     *
137
     * @param string $navigationName Original navigation entity name
138
     * @param string $namespace Namespace
139
     * @return string Correct PHP-supported entity name
140
     */
141
    protected function fullEntityName($navigationName, $namespace = __NAMESPACE__)
142
    {
143
        return '\\'.$namespace.'\\'.$this->entityName($navigationName);
144
    }
145
146
    /**
147
     * Get correct field name.
148
     *
149
     * @param string $fieldName Original field name
150
     * @return string Correct PHP-supported field name
151
     */
152
    protected function fieldName($fieldName)
153
    {
154
        return $fieldName = lcfirst($this->transliterated($fieldName));
0 ignored issues
show
Unused Code introduced by
$fieldName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
155
    }
156
157
    /**
158
     * Get additional field type in form of Field constant name
159
     * by database additional field type identifier.
160
     *
161
     * @param integer $fieldType Additional field type identifier
162
     * @return string Additional field type constant
163
     */
164
    protected function additionalFieldType($fieldType)
165
    {
166
        return 'Field::'.$this->constantNameByValue($fieldType);
167
    }
168
169
    /**
170
     * Generate Query::where() analog for specific field.
171
     *
172
     * @param string $fieldName Field name
173
     * @param string $fieldId Field primary identifier
174
     * @param string $fieldType Field PHP type
175
     * @return string Generated PHP method code
176
     */
177
    protected function generateFieldConditionMethod($fieldName, $fieldId, $fieldType)
178
    {
179
        $code = "\n\t" . '/**';
180
        $code .= "\n\t" . ' * Add '.$fieldName.'(#' . $fieldId . ') field query condition.';
181
        $code .= "\n\t" . ' * @param '.$fieldType.' $value Field value';
182
        $code .= "\n\t" . ' * @return $this Chaining';
183
        $code .= "\n\t" . ' * @see Generic::where()';
184
        $code .= "\n\t" . ' */';
185
        $code .= "\n\t" . 'public function ' . $fieldName . '($value, $relation = ArgumentInterface::EQUAL)';
186
        $code .= "\n\t" . "{";
187
        $code .= "\n\t\t" . 'return $this->where("'.$fieldName.'", $value, $relation);';
188
189
        return $code . "\n\t" . "}"."\n";
190
    }
191
192
    /**
193
     * Generate Query::where() analog for specific field.
194
     *
195
     * @param string $fieldName Field name
196
     * @param string $fieldId Field primary identifier
197
     * @param string $fieldType Field PHP type
198
     * @return string Generated PHP method code
199
     */
200
    protected function generateLocalizedFieldConditionMethod($fieldName, $fieldId, $fieldType)
201
    {
202
        $code = "\n\t" . '/**';
203
        $code .= "\n\t" . ' * Add '.$fieldName.'(#' . $fieldId . ') field query condition.';
204
        $code .= "\n\t" . ' * @param '.Field::phpType($fieldType).' $value Field value';
205
        $code .= "\n\t" . ' * @return $this Chaining';
206
        $code .= "\n\t" . ' * @see Generic::where()';
207
        $code .= "\n\t" . ' */';
208
        $code .= "\n\t" . 'public function ' . $fieldName . '($value)';
209
        $code .= "\n\t" . "{";
210
        $code .= "\n\t\t" . 'return $this->where("'.$fieldName.'", $value);';
211
212
        return $code . "\n\t" . "}"."\n";
213
    }
214
215
    /**
216
     * Generate FieldsTable::values() analog for specific field.
217
     *
218
     * @param string $fieldName Field name
219
     * @param string $fieldId Field primary identifier
220
     * @param string $fieldType Field PHP type
221
     * @return string Generated PHP method code
222
     */
223
    protected function generateTableFieldMethod($fieldName, $fieldId, $fieldType)
224
    {
225
        $code = "\n\t" . '/**';
226
        $code .= "\n\t" . ' * Get table column '.$fieldName.'(#' . $fieldId . ') values.';
227
        $code .= "\n\t" . ' * @return array Collection('.Field::phpType($fieldType).') of table column values';
228
        $code .= "\n\t" . ' */';
229
        $code .= "\n\t" . 'public function ' . $fieldName . '()';
230
        $code .= "\n\t" . "{";
231
        $code .= "\n\t\t" . 'return $this->values('.$fieldId.');';
232
233
        return $code . "\n\t" . "}"."\n";
234
    }
235
236
    /**
237
     * Create fields table row PHP class code.
238
     *
239
     * @param string $navigationName Original entity name
240
     * @param string $entityName PHP entity name
241
     * @param array $navigationFields Collection of entity additional fields
242
     * @return string Generated entity query PHP class code
243
     */
244
    protected function createTableRowClass($navigationName, $entityName, $navigationFields)
245
    {
246
        $class = "\n";
247
        $class .= "\n" . '/**';
248
        $class .= "\n" . ' * Class for getting "'.$navigationName.'" fields table rows';
249
        $class .= "\n" . ' */';
250
        $class .= "\n" . 'class ' . $entityName . ' extends Row';
251
        $class .= "\n" . '{';
252
253
        // Iterate additional fields
254
        $constants = '';
255
        $variables = '';
256
        foreach ($navigationFields as $fieldID => $fieldRow) {
257
            $fieldName = $this->fieldName($fieldRow['Name']);
258
259
            $constants .= "\n\t" . '/** ' . Field::phpType($fieldRow['Type']) . ' '.$fieldRow['Description'].' Field #' . $fieldID . ' variable name */';
260
            // Store original field name
261
            $constants .= "\n\t" . 'const F_' . strtoupper($fieldName) . ' = "'.$fieldName.'";';
262
263
            $variables .= "\n\t" . '/** ' . Field::phpType($fieldRow['Type']) . ' '.$fieldRow['Description'].' Field #' . $fieldID . ' row value */';
264
            $variables .= "\n\t" . 'public $' . $fieldName . ';';
265
        }
266
267
        $class .= $constants;
268
        $class .= "\n\t";
269
        $class .= $variables;
270
        $class .= "\n" . '}';
271
272
        return $class;
273
    }
274
275
    /**
276
     * Create fields table PHP class code.
277
     *
278
     * @param integer $navigationID     Entity navigation identifier
279
     * @param string  $navigationName   Original entity name
280
     * @param string  $entityName       PHP entity name
281
     * @param array   $navigationFields Collection of entity additional fields
282
     * @param string  $rowClassName Row class name
283
     *
284
     * @return string Generated entity query PHP class code
285
     * @throws exception\AdditionalFieldTypeNotFound
286
     */
287
    protected function createTableClass($navigationID, $navigationName, $entityName, $navigationFields, $rowClassName)
288
    {
289
        $this->generator
290
            ->multiComment(array('Class for getting "'.$navigationName.'" fields table'))
291
            ->defClass($entityName, 'FieldsTable');
292
293
        // Iterate additional fields
294
        $fields = array();
295
        foreach ($navigationFields as $fieldID => $fieldRow) {
296
            $fieldName = $this->fieldName($fieldRow['Name']);
297
298
            $this->generator
299
                ->text($this->generateTableFieldMethod(
300
                    $fieldName,
301
                    $fieldRow[Field::F_PRIMARY],
302
                    $fieldRow[Field::F_TYPE]
303
                ))
304
                ->commentVar(Field::phpType($fieldRow['Type']), $fieldRow['Description'] . ' Field #' . $fieldID . ' variable name')
305
                ->defClassConst('F_' . $fieldName, $fieldName);
306
307
            // Collection original to new one field names
308
            $fields[$fieldRow['Name']] = $fieldName;
309
        }
310
311
        // TODO: Add generator method generation logic
312
        $class = "\n\t".'/**';
313
        $class .= "\n\t".' * @param QueryInterface $query Database query instance';
314
        $class .= "\n\t".' * @param ViewInterface $renderer Rendering instance';
315
        $class .= "\n\t".' * @param integer $entityID Entity identifier to whom this table belongs';
316
        $class .= "\n\t".' * @param string $locale Localization identifier';
317
        $class .= "\n\t".' */';
318
        $class .= "\n\t".'public function __construct(QueryInterface $query, ViewInterface $renderer, $entityID, $locale = null)';
319
        $class .= "\n\t".'{';
320
        $class .= "\n\t\t".'parent::__construct($query, $renderer, static::$navigationIDs, $entityID, $locale);';
321
        $class .= "\n\t".'}'."\n";
322
323
        $this->generator->text($class);
324
325
        return $this->generator
326
            ->commentVar('array', 'Collection of real additional field names')
327
            ->defClassVar('$fieldsRealNames', 'public static', $fields)
0 ignored issues
show
Documentation introduced by
$fields is of type array, but the function expects a string|null.

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...
328
            ->commentVar('array', 'Collection of navigation identifiers')
329
            ->defClassVar('$navigationIDs', 'protected static', array($navigationID))
0 ignored issues
show
Documentation introduced by
array($navigationID) is of type array<integer,integer,{"0":"integer"}>, but the function expects a string|null.

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...
330
            ->commentVar('string', 'Row class name')
331
            ->defClassVar('$identifier', 'protected', $this->fullEntityName($rowClassName))
332
            ->endClass()
333
            ->flush();
334
    }
335
336
    /**
337
     * Create entity PHP class code.
338
     *
339
     * @param Metadata $metadata Entity metadata
340
     * @return string Generated entity query PHP class code
341
     */
342
    protected function createEntityClass(Metadata $metadata)
343
    {
344
        /**
345
         * TODO: Parent problem
346
         * Should be changed to merging fields instead of extending with OOP for structure_relation support
347
         * or creating traits and using them on shared parent entities.
348
         */
349
350
        $this->generator
351
            ->multiComment(array('"'.$metadata->entityRealName.'" entity class'))
352
            ->defClass($metadata->entity, null !== $metadata->parent ? $metadata->parent->className : 'Entity')
353
            ->commentVar('string', '@deprecated Entity full class name, use ::class')
354
            ->defClassConst('ENTITY', $metadata->className)
355
            ->commentVar('string', 'Entity manager full class name')
356
            ->defClassConst('MANAGER', $metadata->className.'Query')
357
            ->commentVar('string', 'Entity database identifier')
358
            ->defClassConst('IDENTIFIER', $metadata->entityID)
359
            ->commentVar('string', 'Not transliterated entity name')
360
            ->defClassVar('$viewName', 'protected static', $metadata->entityRealName);
361
362
        foreach ($metadata->allFieldIDs as $fieldID => $fieldName) {
363
            $this->generator
364
                ->commentVar('string', $metadata->fieldDescriptions[$fieldID].' variable name')
365
                ->defClassConst('F_' . $fieldName, $fieldName)
366
                ->commentVar($metadata->allFieldTypes[$fieldID], $metadata->fieldDescriptions[$fieldID])
367
                ->defClassVar('$' . $fieldName, 'public');
368
        }
369
370
        return $this->generator
371
            ->defClassVar('$_sql_select', 'public static ', $metadata->arSelect)
0 ignored issues
show
Documentation introduced by
$metadata->arSelect is of type array, but the function expects a string|null.

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...
372
            ->defClassVar('$_attributes', 'public static ', $metadata->arAttributes)
0 ignored issues
show
Documentation introduced by
$metadata->arAttributes is of type array, but the function expects a string|null.

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...
373
            ->defClassVar('$_map', 'public static ', $metadata->arMap)
0 ignored issues
show
Documentation introduced by
$metadata->arMap is of type array, but the function expects a string|null.

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...
374
            ->defClassVar('$_sql_from', 'public static ', $metadata->arFrom)
0 ignored issues
show
Documentation introduced by
$metadata->arFrom is of type array, but the function expects a string|null.

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...
375
            ->defClassVar('$_own_group', 'public static ', $metadata->arGroup)
0 ignored issues
show
Documentation introduced by
$metadata->arGroup is of type array, but the function expects a string|null.

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...
376
            ->defClassVar('$_relation_alias', 'public static ', $metadata->arRelationAlias)
0 ignored issues
show
Documentation introduced by
$metadata->arRelationAlias is of type array, but the function expects a string|null.

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...
377
            ->defClassVar('$_relation_type', 'public static ', $metadata->arRelationType)
0 ignored issues
show
Documentation introduced by
$metadata->arRelationType is of type array, but the function expects a string|null.

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...
378
            ->defClassVar('$_relations', 'public static ', $metadata->arRelations)
0 ignored issues
show
Documentation introduced by
$metadata->arRelations is of type array, but the function expects a string|null.

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...
379
            ->defClassVar('$fieldIDs', 'protected static ', $metadata->allFieldIDs)
0 ignored issues
show
Documentation introduced by
$metadata->allFieldIDs is of type array, but the function expects a string|null.

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...
380
            ->defClassVar('$fieldValueColumns', 'protected static ', $metadata->allFieldValueColumns)
0 ignored issues
show
Documentation introduced by
$metadata->allFieldValueColumns is of type array, but the function expects a string|null.

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...
381
            ->endClass()
382
            ->flush();
383
    }
384
385
    /**
386
     * Create entity query PHP class code.
387
     *
388
     * @param Metadata $metadata Entity metadata
389
     * @param string   $suffix Generated class name suffix
390
     * @param string   $defaultParent Parent class name
391
     *
392
     * @return string Generated entity query PHP class code
393
     */
394
    protected function createQueryClass(Metadata $metadata, $suffix = 'Query', $defaultParent = '\samsoncms\api\query\Entity')
395
    {
396
        //$navigationID, $navigationName, $entityName, $navigationFields, $parentClass = '\samsoncms\api\query\Entity'
397
        $this->generator
398
            ->multiComment(array('Class for fetching "'.$metadata->entityRealName.'" instances from database'))
399
            ->defClass($metadata->entity.$suffix, $defaultParent)
400
        ;
401
402
        foreach ($metadata->allFieldIDs as $fieldID => $fieldName) {
403
            // TODO: Add different method generation depending on their field type
404
            $this->generator->text($this->generateFieldConditionMethod(
405
                $fieldName,
406
                $fieldID,
407
                $metadata->allFieldTypes[$fieldID]
408
            ));
409
        }
410
411
        return $this->generator
412
            ->commentVar('array', 'Collection of real additional field names')
413
            ->defClassVar('$fieldRealNames', 'public static', $metadata->realNames)
0 ignored issues
show
Documentation introduced by
$metadata->realNames is of type array, but the function expects a string|null.

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...
414
            ->commentVar('array', 'Collection of additional field names')
415
            ->defClassVar('$fieldNames', 'public static', $metadata->allFieldNames)
0 ignored issues
show
Documentation introduced by
$metadata->allFieldNames is of type array, but the function expects a string|null.

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...
416
            // TODO: two above fields should be protected
417
            ->commentVar('array', 'Collection of navigation identifiers')
418
            ->defClassVar('$navigationIDs', 'protected static', array($metadata->entityID))
0 ignored issues
show
Documentation introduced by
array($metadata->entityID) is of type array<integer,string,{"0":"string"}>, but the function expects a string|null.

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...
419
            ->commentVar('string', 'Entity full class name')
420
            ->defClassVar('$identifier', 'protected static', $metadata->className)
421
            ->commentVar('array', 'Collection of localized additional fields identifiers')
422
            ->defClassVar('$localizedFieldIDs', 'protected static', $metadata->localizedFieldIDs)
0 ignored issues
show
Documentation introduced by
$metadata->localizedFieldIDs is of type array, but the function expects a string|null.

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...
423
            ->commentVar('array', 'Collection of NOT localized additional fields identifiers')
424
            ->defClassVar('$notLocalizedFieldIDs', 'protected static', $metadata->notLocalizedFieldIDs)
0 ignored issues
show
Documentation introduced by
$metadata->notLocalizedFieldIDs is of type array, but the function expects a string|null.

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...
425
            ->commentVar('array', 'Collection of localized additional fields identifiers')
426
            ->defClassVar('$fieldIDs', 'protected static', $metadata->allFieldIDs)
0 ignored issues
show
Documentation introduced by
$metadata->allFieldIDs is of type array, but the function expects a string|null.

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...
427
            ->commentVar('array', 'Collection of additional fields value column names')
428
            ->defClassVar('$fieldValueColumns', 'protected static', $metadata->allFieldValueColumns)
0 ignored issues
show
Documentation introduced by
$metadata->allFieldValueColumns is of type array, but the function expects a string|null.

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...
429
            ->endClass()
430
            ->flush()
431
        ;
432
    }
433
434
    /** @return string Entity state hash */
435
    public function entityHash()
436
    {
437
        // Получим информацию о всех таблицах из БД
438
        return md5(serialize($this->database->fetch(
439
            'SELECT `TABLES`.`TABLE_NAME` as `TABLE_NAME`
440
              FROM `information_schema`.`TABLES` as `TABLES`
441
              WHERE `TABLES`.`TABLE_SCHEMA`="' . $this->database->database() . '";'
442
        )));
443
    }
444
445
    /**
446
     * Find entity parent.
447
     *
448
     * @param $entityID
449
     *
450
     * @return null|int Parent entity identifier
451
     */
452
    public function entityParent($entityID)
453
    {
454
        $parentData = $this->database->fetch('
455
SELECT *
456
FROM structure_relation as sm
457
JOIN structure as s ON s.StructureID = sm.parent_id
458
WHERE sm.child_id = "' . $entityID . '"
459
AND s.StructureID != "' . $entityID . '"
460
');
461
462
        // Get parent entity identifier
463
        return count($parentData) ? $parentData[0]['StructureID'] : null;
464
    }
465
466
    /** @return array Get collection of navigation objects */
467
    protected function entityNavigations($type = 0)
468
    {
469
        return $this->database->fetch('
470
        SELECT * FROM `structure`
471
        WHERE `Active` = "1" AND `Type` = "'.$type.'"
472
        ORDER BY `ParentID` ASC
473
        ');
474
    }
475
476
    /** @return array Collection of navigation additional fields */
477
    protected function navigationFields($navigationID)
478
    {
479
        $return = array();
480
        // TODO: Optimize queries make one single query with only needed data
481
        foreach ($this->database->fetch('SELECT * FROM `structurefield` WHERE `StructureID` = "' . $navigationID . '" AND `Active` = "1"') as $fieldStructureRow) {
482
            foreach ($this->database->fetch('SELECT * FROM `field` WHERE `FieldID` = "' . $fieldStructureRow['FieldID'] . '"') as $fieldRow) {
483
                $return[$fieldRow['FieldID']] = $fieldRow;
484
            }
485
        }
486
487
        return $return;
488
    }
489
490
    /**
491
     * Generate entity classes.
492
     *
493
     * @param string $namespace Base namespace for generated classes
494
     * @return string Generated PHP code for entity classes
495
     */
496
    public function createEntityClasses($namespace = __NAMESPACE__)
497
    {
498
        $classes = "\n" . 'namespace ' . $namespace . ';';
499
        $classes .= "\n";
500
        $classes .= "\n" . 'use '.$namespace.'\renderable\FieldsTable;';
501
        $classes .= "\n" . 'use '.$namespace.'\field\Row;';
502
        $classes .= "\n" . 'use \samsonframework\core\ViewInterface;';
503
        $classes .= "\n" . 'use \samsonframework\orm\ArgumentInterface;';
504
        $classes .= "\n" . 'use \samsonframework\orm\QueryInterface;';
505
        $classes .= "\n" . 'use \samson\activerecord\dbQuery;';
506
        $classes .= "\n";
507
508
        // Iterate all structures, parents first
509
        foreach ($this->entityNavigations() as $structureRow) {
510
            // Fill in entity metadata
511
            $metadata = new Metadata();
512
            // Get CapsCase and transliterated entity name
513
            $metadata->entity = $this->entityName($structureRow['Name']);
514
            // Try to find entity parent identifier for building future relations
515
            $metadata->parentID = $this->entityParent($structureRow['StructureID']);
516
517
            // TODO: Add multiple parent and fetching their data in a loop
518
519
            // Set pointer to parent entity
520
            if (null !== $metadata->parentID) {
521
                if (array_key_exists($metadata->parentID, $this->metadata)) {
522
                    $metadata->parent = $this->metadata[$metadata->parentID];
523
                    // Add all parent metadata to current object
524
                    $metadata->realNames = $metadata->parent->realNames;
525
                    $metadata->allFieldIDs = $metadata->parent->allFieldIDs;
526
                    $metadata->allFieldNames = $metadata->parent->allFieldNames;
527
                    $metadata->allFieldValueColumns = $metadata->parent->allFieldValueColumns;
528
                    $metadata->allFieldTypes = $metadata->parent->allFieldTypes;
529
                    $metadata->fieldDescriptions = $metadata->parent->fieldDescriptions;
530
                    $metadata->localizedFieldIDs = $metadata->parent->localizedFieldIDs;
531
                    $metadata->notLocalizedFieldIDs = $metadata->parent->notLocalizedFieldIDs;
532
                } else {
533
                    throw new ParentEntityNotFound($metadata->parentID);
534
                }
535
            }
536
537
            // Store entity original data
538
            $metadata->entityRealName = $structureRow['Name'];
539
            $metadata->entityID = $structureRow['StructureID'];
540
            $metadata->className = $this->fullEntityName($metadata->entity, __NAMESPACE__);
541
542
            // Get old AR collections of metadata
543
            $metadata->arSelect = \samson\activerecord\material::$_sql_select;
544
            $metadata->arAttributes = \samson\activerecord\material::$_attributes;
545
            $metadata->arMap = \samson\activerecord\material::$_map;
546
            $metadata->arFrom = \samson\activerecord\material::$_sql_from;
547
            $metadata->arGroup = \samson\activerecord\material::$_own_group;
548
            $metadata->arRelationAlias = \samson\activerecord\material::$_relation_alias;
549
            $metadata->arRelationType = \samson\activerecord\material::$_relation_type;
550
            $metadata->arRelations = \samson\activerecord\material::$_relations;
551
552
            // Add SamsonCMS material needed data
553
            $metadata->arSelect['this'] = ' STRAIGHT_JOIN ' . $metadata->arSelect['this'];
554
            $metadata->arFrom['this'] .= "\n" .
555
                'LEFT JOIN ' . dbMySQLConnector::$prefix . 'materialfield as _mf
556
                ON ' . dbMySQLConnector::$prefix . 'material.MaterialID = _mf.MaterialID';
557
            $metadata->arGroup[] = dbMySQLConnector::$prefix . 'material.MaterialID';
558
559
            // Iterate entity fields
560
            foreach ($this->navigationFields($structureRow['StructureID']) as $fieldID => $fieldRow) {
561
                // Get camelCase and transliterated field name
562
                $fieldName = $this->fieldName($fieldRow['Name']);
563
564
                // Store field metadata
565
                $metadata->realNames[$fieldRow['Name']] = $fieldName;
566
                $metadata->allFieldIDs[$fieldID] = $fieldName;
567
                $metadata->allFieldNames[$fieldName] = $fieldID;
568
                $metadata->allFieldValueColumns[$fieldID] = Field::valueColumn($fieldRow[Field::F_TYPE]);
569
                $metadata->allFieldTypes[$fieldID] = Field::phpType($fieldRow['Type']);
570
                $metadata->fieldDescriptions[$fieldID] = $fieldRow['Description'] . ', '.$fieldRow['Name'].'#' . $fieldID;
571
572
                // Fill localization fields collections
573
                if ($fieldRow[Field::F_LOCALIZED] === 1) {
574
                    $metadata->localizedFieldIDs[$fieldID] = $fieldName;
575
                } else {
576
                    $metadata->notLocalizedFieldIDs[$fieldID] = $fieldName;
577
                }
578
579
                // Set old AR collections of metadata
580
                $metadata->arAttributes[$fieldName] = $fieldName;
581
                $metadata->arMap[$fieldName] = dbMySQLConnector::$prefix . 'material.' . $fieldName;
582
583
                // Add additional field column to entity query
584
                $equal = '((_mf.FieldID = ' . $fieldID . ')&&(_mf.locale ' . ($fieldRow['local'] ? ' = "@locale"' : 'IS NULL') . '))';
585
                $metadata->arSelect['this'] .= "\n\t\t" . ',MAX(IF(' . $equal . ', _mf.`' . Field::valueColumn($fieldRow['Type']) . '`, NULL)) as `' . $fieldName . '`';
586
            }
587
588
            // Store metadata by entity identifier
589
            $this->metadata[$structureRow['StructureID']] = $metadata;
590
        }
591
592
        // Iterate all entities metadata
593
        foreach ($this->metadata as $metadata) {
594
            $classes .= $this->createEntityClass($metadata);
595
            $classes .= $this->createQueryClass($metadata);
596
            $classes .= $this->createQueryClass($metadata, 'Collection', '\samsoncms\api\renderable\Collection');
597
        }
598
599
        // Iterate table structures
600
        foreach ($this->entityNavigations(2) as $structureRow) {
601
            $navigationFields = $this->navigationFields($structureRow['StructureID']);
602
            $entityName = $this->entityName($structureRow['Name']);
603
604
            $rowClassName = $entityName.'TableRow';
605
606
            $classes .= $this->createTableRowClass(
607
                $structureRow['Name'],
608
                $rowClassName,
609
                $navigationFields
610
            );
611
612
            $classes .= $this->createTableClass(
613
                $structureRow['StructureID'],
614
                $structureRow['Name'],
615
                $entityName.'Table',
616
                $navigationFields,
617
                $rowClassName
618
            );
619
620
        }
621
622
        // Make correct code formatting
623
        return str_replace("\t", '    ', $classes);
624
    }
625
626
    /**
627
     * Generator constructor.
628
     * @param DatabaseInterface $database Database instance
629
     */
630
    public function __construct(DatabaseInterface $database)
631
    {
632
        $this->generator = new \samsonphp\generator\Generator();
633
        $this->database = $database;
634
    }
635
}
636
637
//[PHPCOMPRESSOR(remove,end)]
638