Completed
Pull Request — master (#20)
by
unknown
05:38
created

Generator::generateConstructorTableClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 15
rs 9.4285
cc 1
eloc 12
nc 1
nop 0
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
     * Generate constructor for table class.
238
     */
239
    protected function generateConstructorTableClass()
240
    {
241
        $class = "\n\t".'/**';
242
        $class .= "\n\t".' * @param QueryInterface $query Database query instance';
243
        $class .= "\n\t".' * @param ViewInterface $renderer Rendering instance';
244
        $class .= "\n\t".' * @param integer $entityID Entity identifier to whom this table belongs';
245
        $class .= "\n\t".' * @param string $locale Localization identifier';
246
        $class .= "\n\t".' */';
247
        $class .= "\n\t".'public function __construct(QueryInterface $query, ViewInterface $renderer, $entityID, $locale = null)';
248
        $class .= "\n\t".'{';
249
        $class .= "\n\t\t".'parent::__construct($query, $renderer, static::$navigationIDs, $entityID, $locale);';
250
        $class .= "\n\t".'}'."\n";
251
252
        return $class;
253
    }
254
255
    /**
256
     * Create fields table row PHP class code.
257
     *
258
     * @param Metadata $metadata metadata of entity
259
     * @return string Generated entity query PHP class code
260
     * @throws exception\AdditionalFieldTypeNotFound
261
     */
262
    protected function createTableRowClass(Metadata $metadata)
263
    {
264
        $this->generator
265
            ->multiComment(array('Class for getting "' . $metadata->entityRealName . '" fields table rows'))
266
            ->defClass($this->entityName($metadata->entityRealName) . 'TableRow', 'Row');
267
268
        $fieldIDs = array();
269
        foreach ($this->navigationFields($metadata->entityID) as $fieldID => $fieldRow) {
270
            $fieldName = $this->fieldName($fieldRow['Name']);
271
272
            // Fill field ids array
273
            $fieldIDs[$fieldName] = $fieldID;
274
275
            $this->generator
276
                ->commentVar($metadata->allFieldTypes[$fieldID], $fieldRow['Description'] . ' Field #' . $fieldID . ' variable name')
277
                ->defClassConst('F_' . strtoupper($fieldName), $fieldName)
278
                ->commentVar($metadata->allFieldTypes[$fieldID], $fieldRow['Description'] . ' Field #' . $fieldID . ' row value')
279
                ->defVar('public $' . $fieldName)
280
                ->text("\n");
281
        }
282
283
        return $this->generator
284
            ->commentVar('array', 'Collection of additional fields identifiers')
285
            ->defClassVar('$fieldIDs', 'public static', $fieldIDs)
0 ignored issues
show
Documentation introduced by
$fieldIDs 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...
286
            ->endClass()
287
            ->flush();
288
    }
289
290
    /**
291
     * Create fields table PHP class code.
292
     *
293
     * @param Metadata $metadata metadata of entity
294
     *
295
     * @return string Generated entity query PHP class code
296
     * @throws exception\AdditionalFieldTypeNotFound
297
     */
298
    protected function createTableClass(Metadata $metadata)
299
    {
300
        $this->generator
301
            ->multiComment(array('Class for getting "'.$metadata->entityRealName.'" fields table'))
302
            ->defClass($this->entityName($metadata->entityRealName) . 'Table', 'FieldsTable');
303
304
        // Iterate additional fields
305
        $fields = array();
306
        foreach ($this->navigationFields($metadata->entityID) as $fieldID => $fieldRow) {
307
            $fieldName = $this->fieldName($fieldRow['Name']);
308
309
            $this->generator
310
                ->text($this->generateTableFieldMethod(
311
                    $fieldName,
312
                    $fieldRow[Field::F_PRIMARY],
313
                    $fieldRow[Field::F_TYPE]
314
                ))
315
                ->commentVar($metadata->allFieldTypes[$fieldID], $fieldRow['Description'] . ' Field #' . $fieldID . ' variable name')
316
                ->defClassConst('F_' . $fieldName, $fieldName);
317
318
            // Collection original to new one field names
319
            $fields[$fieldRow['Name']] = $fieldName;
320
        }
321
322
        // TODO: Add generator method generation logic
323
        $constructor = $this->generateConstructorTableClass();
324
325
        $this->generator->text($constructor);
326
327
        return $this->generator
328
            ->commentVar('array', 'Collection of real additional field names')
329
            ->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...
330
            ->commentVar('array', 'Collection of navigation identifiers')
331
            ->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...
332
            ->commentVar('string', 'Row class name')
333
            ->defClassVar('$identifier', 'protected', $this->fullEntityName($this->entityName($metadata->entityRealName) . 'TableRow'))
334
            ->endClass()
335
            ->flush();
336
    }
337
338
    /**
339
     * Create entity PHP class code.
340
     *
341
     * @param Metadata $metadata Entity metadata
342
     * @return string Generated entity query PHP class code
343
     */
344
    protected function createEntityClass(Metadata $metadata)
345
    {
346
        /**
347
         * TODO: Parent problem
348
         * Should be changed to merging fields instead of extending with OOP for structure_relation support
349
         * or creating traits and using them on shared parent entities.
350
         */
351
352
        $this->generator
353
            ->multiComment(array('"'.$metadata->entityRealName.'" entity class'))
354
            ->defClass($metadata->entity, null !== $metadata->parent ? $metadata->parent->className : 'Entity')
355
            ->commentVar('string', '@deprecated Entity full class name, use ::class')
356
            ->defClassConst('ENTITY', $metadata->className)
357
            ->commentVar('string', 'Entity manager full class name')
358
            ->defClassConst('MANAGER', $metadata->className.'Query')
359
            ->commentVar('string', 'Entity database identifier')
360
            ->defClassConst('IDENTIFIER', $metadata->entityID)
361
            ->commentVar('string', 'Not transliterated entity name')
362
            ->defClassVar('$viewName', 'protected static', $metadata->entityRealName);
363
364
        foreach ($metadata->allFieldIDs as $fieldID => $fieldName) {
365
            $this->generator
366
                ->commentVar('string', $metadata->fieldDescriptions[$fieldID].' variable name')
367
                ->defClassConst('F_' . $fieldName, $fieldName)
368
                ->commentVar($metadata->allFieldTypes[$fieldID], $metadata->fieldDescriptions[$fieldID])
369
                ->defClassVar('$' . $fieldName, 'public');
370
        }
371
372
        return $this->generator
373
            ->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...
374
            ->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...
375
            ->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...
376
            ->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...
377
            ->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...
378
            ->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...
379
            ->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...
380
            ->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...
381
            ->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...
382
            ->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...
383
            ->endClass()
384
            ->flush();
385
    }
386
387
    /**
388
     * Create entity query PHP class code.
389
     *
390
     * @param Metadata $metadata Entity metadata
391
     * @param string   $suffix Generated class name suffix
392
     * @param string   $defaultParent Parent class name
393
     *
394
     * @return string Generated entity query PHP class code
395
     */
396
    protected function createQueryClass(Metadata $metadata, $suffix = 'Query', $defaultParent = '\samsoncms\api\query\Entity')
397
    {
398
        //$navigationID, $navigationName, $entityName, $navigationFields, $parentClass = '\samsoncms\api\query\Entity'
399
        $this->generator
400
            ->multiComment(array('Class for fetching "'.$metadata->entityRealName.'" instances from database'))
401
            ->defClass($metadata->entity.$suffix, $defaultParent)
402
        ;
403
404
        foreach ($metadata->allFieldIDs as $fieldID => $fieldName) {
405
            // TODO: Add different method generation depending on their field type
406
            $this->generator->text($this->generateFieldConditionMethod(
407
                $fieldName,
408
                $fieldID,
409
                $metadata->allFieldTypes[$fieldID]
410
            ));
411
        }
412
413
        return $this->generator
414
            ->commentVar('array', 'Collection of real additional field names')
415
            ->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...
416
            ->commentVar('array', 'Collection of additional field names')
417
            ->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...
418
            // TODO: two above fields should be protected
419
            ->commentVar('array', 'Collection of navigation identifiers')
420
            ->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...
421
            ->commentVar('string', 'Entity full class name')
422
            ->defClassVar('$identifier', 'protected static', $metadata->className)
423
            ->commentVar('array', 'Collection of localized additional fields identifiers')
424
            ->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...
425
            ->commentVar('array', 'Collection of NOT localized additional fields identifiers')
426
            ->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...
427
            ->commentVar('array', 'Collection of localized additional fields identifiers')
428
            ->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...
429
            ->commentVar('array', 'Collection of additional fields value column names')
430
            ->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...
431
            ->endClass()
432
            ->flush()
433
        ;
434
    }
435
436
    /** @return string Entity state hash */
437
    public function entityHash()
438
    {
439
        // Получим информацию о всех таблицах из БД
440
        return md5(serialize($this->database->fetch(
441
            'SELECT `TABLES`.`TABLE_NAME` as `TABLE_NAME`
442
              FROM `information_schema`.`TABLES` as `TABLES`
443
              WHERE `TABLES`.`TABLE_SCHEMA`="' . $this->database->database() . '";'
444
        )));
445
    }
446
447
    /**
448
     * Find entity parent.
449
     *
450
     * @param $entityID
451
     *
452
     * @return null|int Parent entity identifier
453
     */
454
    public function entityParent($entityID)
455
    {
456
        $parentData = $this->database->fetch('
457
SELECT *
458
FROM structure_relation as sm
459
JOIN structure as s ON s.StructureID = sm.parent_id
460
WHERE sm.child_id = "' . $entityID . '"
461
AND s.StructureID != "' . $entityID . '"
462
');
463
464
        // Get parent entity identifier
465
        return count($parentData) ? $parentData[0]['StructureID'] : null;
466
    }
467
468
    /** @return array Get collection of navigation objects */
469
    protected function entityNavigations($type = 0)
470
    {
471
        return $this->database->fetch('
472
        SELECT * FROM `structure`
473
        WHERE `Active` = "1" AND `Type` = "'.$type.'"
474
        ORDER BY `ParentID` ASC
475
        ');
476
    }
477
478
    /** @return array Collection of navigation additional fields */
479
    protected function navigationFields($navigationID)
480
    {
481
        $return = array();
482
        // TODO: Optimize queries make one single query with only needed data
483
        foreach ($this->database->fetch('SELECT * FROM `structurefield` WHERE `StructureID` = "' . $navigationID . '" AND `Active` = "1"') as $fieldStructureRow) {
484
            foreach ($this->database->fetch('SELECT * FROM `field` WHERE `FieldID` = "' . $fieldStructureRow['FieldID'] . '"') as $fieldRow) {
485
                $return[$fieldRow['FieldID']] = $fieldRow;
486
            }
487
        }
488
489
        return $return;
490
    }
491
492
    /**
493
     * Generate entity classes.
494
     *
495
     * @param string $namespace Base namespace for generated classes
496
     * @return string Generated PHP code for entity classes
497
     */
498
    public function createEntityClasses($namespace = __NAMESPACE__)
499
    {
500
        $classes = "\n" . 'namespace ' . $namespace . ';';
501
        $classes .= "\n";
502
        $classes .= "\n" . 'use '.$namespace.'\renderable\FieldsTable;';
503
        $classes .= "\n" . 'use '.$namespace.'\field\Row;';
504
        $classes .= "\n" . 'use \samsonframework\core\ViewInterface;';
505
        $classes .= "\n" . 'use \samsonframework\orm\ArgumentInterface;';
506
        $classes .= "\n" . 'use \samsonframework\orm\QueryInterface;';
507
        $classes .= "\n" . 'use \samson\activerecord\dbQuery;';
508
        $classes .= "\n";
509
510
        // Iterate all metadata types
511
        foreach (Metadata::$types as $type) {
512
513
            // Iterate all structures, parents first
514
            foreach ($this->entityNavigations($type) as $structureRow) {
515
516
                // Fill in entity metadata
517
                $metadata = new Metadata($type);
518
519
                // Get CapsCase and transliterated entity name
520
                $metadata->entity = $this->entityName($structureRow['Name']);
521
                // Try to find entity parent identifier for building future relations
522
                $metadata->parentID = $this->entityParent($structureRow['StructureID']);
523
524
                // TODO: Add multiple parent and fetching their data in a loop
525
526
                // Set pointer to parent entity
527
                if (null !== $metadata->parentID) {
528
                    if (array_key_exists($metadata->parentID, $this->metadata)) {
529
                        $metadata->parent = $this->metadata[$metadata->parentID];
530
                        // Add all parent metadata to current object
531
                        $metadata->realNames = $metadata->parent->realNames;
532
                        $metadata->allFieldIDs = $metadata->parent->allFieldIDs;
533
                        $metadata->allFieldNames = $metadata->parent->allFieldNames;
534
                        $metadata->allFieldValueColumns = $metadata->parent->allFieldValueColumns;
535
                        $metadata->allFieldTypes = $metadata->parent->allFieldTypes;
536
                        $metadata->fieldDescriptions = $metadata->parent->fieldDescriptions;
537
                        $metadata->localizedFieldIDs = $metadata->parent->localizedFieldIDs;
538
                        $metadata->notLocalizedFieldIDs = $metadata->parent->notLocalizedFieldIDs;
539
                    } else {
540
                        throw new ParentEntityNotFound($metadata->parentID);
541
                    }
542
                }
543
544
                // Store entity original data
545
                $metadata->entityRealName = $structureRow['Name'];
546
                $metadata->entityID = $structureRow['StructureID'];
547
                $metadata->className = $this->fullEntityName($metadata->entity, __NAMESPACE__);
548
549
                // Get old AR collections of metadata
550
                $metadata->arSelect = \samson\activerecord\material::$_sql_select;
551
                $metadata->arAttributes = \samson\activerecord\material::$_attributes;
552
                $metadata->arMap = \samson\activerecord\material::$_map;
553
                $metadata->arFrom = \samson\activerecord\material::$_sql_from;
554
                $metadata->arGroup = \samson\activerecord\material::$_own_group;
555
                $metadata->arRelationAlias = \samson\activerecord\material::$_relation_alias;
556
                $metadata->arRelationType = \samson\activerecord\material::$_relation_type;
557
                $metadata->arRelations = \samson\activerecord\material::$_relations;
558
559
                // Add SamsonCMS material needed data
560
                $metadata->arSelect['this'] = ' STRAIGHT_JOIN ' . $metadata->arSelect['this'];
561
                $metadata->arFrom['this'] .= "\n" .
562
                    'LEFT JOIN ' . dbMySQLConnector::$prefix . 'materialfield as _mf
563
                ON ' . dbMySQLConnector::$prefix . 'material.MaterialID = _mf.MaterialID';
564
                $metadata->arGroup[] = dbMySQLConnector::$prefix . 'material.MaterialID';
565
566
                // Iterate entity fields
567
                foreach ($this->navigationFields($structureRow['StructureID']) as $fieldID => $fieldRow) {
568
                    // Get camelCase and transliterated field name
569
                    $fieldName = $this->fieldName($fieldRow['Name']);
570
571
                    // Store field metadata
572
                    $metadata->realNames[$fieldRow['Name']] = $fieldName;
573
                    $metadata->allFieldIDs[$fieldID] = $fieldName;
574
                    $metadata->allFieldNames[$fieldName] = $fieldID;
575
                    $metadata->allFieldValueColumns[$fieldID] = Field::valueColumn($fieldRow[Field::F_TYPE]);
576
                    $metadata->allFieldTypes[$fieldID] = Field::phpType($fieldRow['Type']);
577
                    $metadata->fieldDescriptions[$fieldID] = $fieldRow['Description'] . ', ' . $fieldRow['Name'] . '#' . $fieldID;
578
579
                    // Fill localization fields collections
580
                    if ($fieldRow[Field::F_LOCALIZED] === 1) {
581
                        $metadata->localizedFieldIDs[$fieldID] = $fieldName;
582
                    } else {
583
                        $metadata->notLocalizedFieldIDs[$fieldID] = $fieldName;
584
                    }
585
586
                    // Set old AR collections of metadata
587
                    $metadata->arAttributes[$fieldName] = $fieldName;
588
                    $metadata->arMap[$fieldName] = dbMySQLConnector::$prefix . 'material.' . $fieldName;
589
590
                    // Add additional field column to entity query
591
                    $equal = '((_mf.FieldID = ' . $fieldID . ')&&(_mf.locale ' . ($fieldRow['local'] ? ' = "@locale"' : 'IS NULL') . '))';
592
                    $metadata->arSelect['this'] .= "\n\t\t" . ',MAX(IF(' . $equal . ', _mf.`' . Field::valueColumn($fieldRow['Type']) . '`, NULL)) as `' . $fieldName . '`';
593
                }
594
595
                // Store metadata by entity identifier
596
                $this->metadata[$structureRow['StructureID']] = $metadata;
597
            }
598
        }
599
600
        // Iterate all entities metadata
601
        foreach ($this->metadata as $metadata) {
602
603
            // Generate classes of default type
604
            if ($metadata->type === Metadata::TYPE_DEFAULT) {
605
606
                $classes .= $this->createEntityClass($metadata);
607
                $classes .= $this->createQueryClass($metadata);
608
                $classes .= $this->createQueryClass($metadata, 'Collection', '\samsoncms\api\renderable\Collection');
609
610
                // Generate classes of table type
611
            } else if ($metadata->type === Metadata::TYPE_TABLE) {
612
613
                $classes .= $this->createTableRowClass($metadata);
614
                $classes .= $this->createTableClass($metadata);
615
            }
616
        }
617
618
        // Make correct code formatting
619
        return str_replace("\t", '    ', $classes);
620
    }
621
622
    /**
623
     * Generator constructor.
624
     * @param DatabaseInterface $database Database instance
625
     */
626
    public function __construct(DatabaseInterface $database)
627
    {
628
        $this->generator = new \samsonphp\generator\Generator();
629
        $this->database = $database;
630
    }
631
}
632
633
//[PHPCOMPRESSOR(remove,end)]
634