Passed
Pull Request — master (#21)
by
unknown
03:31
created

Generator::constantNameByValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 13
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: molodyko
5
 * Date: 13.02.2016
6
 * Time: 23:55
7
 */
8
9
namespace samsoncms\api\generator;
10
11
use samson\activerecord\dbMySQLConnector;
12
use samsoncms\api\Field;
13
use samsoncms\api\generator\exception\ParentEntityNotFound;
14
use samsonframework\orm\DatabaseInterface;
15
16
abstract class Generator
17
{
18
    /** @var DatabaseInterface */
19
    protected $database;
20
21
    /** @var \samsonphp\generator\Generator */
22
    protected $generator;
23
24
    /** @var Metadata[] Collection of entities metadata */
25
    protected $metadata;
26
27
    /**
28
     * Generator constructor.
29
     * @param DatabaseInterface $database Database instance
30
     * @throws ParentEntityNotFound
31
     * @throws \samsoncms\api\exception\AdditionalFieldTypeNotFound
32
     */
33
    public function __construct(DatabaseInterface $database)
34
    {
35
        $this->generator = new \samsonphp\generator\Generator();
36
        $this->database = $database;
37
    }
38
39
    /**
40
     * Make correct code formatting
41
     * @param $code
42
     * @return mixed
43
     */
44
    protected function formatTab($code)
45
    {
46
        // Replace indentation
47
        return str_replace("\t", '    ', $code);
48
    }
49
50
    /**
51
     * Fill metadata
52
     *
53
     * @param null $filter Filter navigations
54
     * @throws ParentEntityNotFound
55
     * @throws \samsoncms\api\exception\AdditionalFieldTypeNotFound
56
     */
57
    public function fillMetadata($filter = null)
58
    {
59
        // Iterate all metadata types
60
        foreach (Metadata::$types as $type) {
61
62
            // Iterate all structures, parents first
63
            foreach ($this->entityNavigations($type) as $structureRow) {
64
65
                // If filter is the function and filter return false then skip this structure
66
                if (is_callable($filter) && (false === $filter($structureRow))) {
67
                    continue;
68
                }
69
70
                // Fill in entity metadata
71
                $metadata = new Metadata($type);
72
73
                // Get CapsCase and transliterated entity name
74
                $metadata->entity = $this->entityName($structureRow['Name']);
75
                // Try to find entity parent identifier for building future relations
76
                $metadata->parentID = $this->entityParent($structureRow['StructureID']);
77
                // Generate application from current entity
78
                $metadata->generateApplication = $structureRow['applicationGenerate'];
79
                // Show application from current entity
80
                $metadata->showApplication = $structureRow['applicationOutput'];
81
                // Icon for application from current entity
82
                $metadata->iconApplication = $structureRow['applicationIcon'];
83
                // Render application on main page
84
                $metadata->renderMainApplication = $structureRow['applicationRenderMain'];
85
86
                // TODO: Add multiple parent and fetching their data in a loop
87
88
                // Set pointer to parent entity
89
                if (null !== $metadata->parentID) {
90
                    if (array_key_exists($metadata->parentID, $this->metadata)) {
91
                        $metadata->parent = $this->metadata[$metadata->parentID];
92
                        // Add all parent metadata to current object
93
                        $metadata->realNames = $metadata->parent->realNames;
94
                        $metadata->allFieldIDs = $metadata->parent->allFieldIDs;
95
                        $metadata->allFieldNames = $metadata->parent->allFieldNames;
96
                        $metadata->allFieldValueColumns = $metadata->parent->allFieldValueColumns;
97
                        $metadata->allFieldTypes = $metadata->parent->allFieldTypes;
98
                        $metadata->fieldDescriptions = $metadata->parent->fieldDescriptions;
99
                        $metadata->localizedFieldIDs = $metadata->parent->localizedFieldIDs;
100
                        $metadata->notLocalizedFieldIDs = $metadata->parent->notLocalizedFieldIDs;
101
                    } else {
102
                        throw new ParentEntityNotFound($metadata->parentID);
103
                    }
104
                }
105
106
                // Store entity original data
107
                $metadata->entityRealName = $structureRow['Name'];
108
                $metadata->entityID = $structureRow['StructureID'];
109
110
                // Get old AR collections of metadata
111
                $metadata->arSelect = \samson\activerecord\material::$_sql_select;
112
                $metadata->arAttributes = \samson\activerecord\material::$_attributes;
113
                $metadata->arMap = \samson\activerecord\material::$_map;
114
                $metadata->arFrom = \samson\activerecord\material::$_sql_from;
115
                $metadata->arGroup = \samson\activerecord\material::$_own_group;
116
                $metadata->arRelationAlias = \samson\activerecord\material::$_relation_alias;
117
                $metadata->arRelationType = \samson\activerecord\material::$_relation_type;
118
                $metadata->arRelations = \samson\activerecord\material::$_relations;
119
120
                // Add SamsonCMS material needed data
121
                $metadata->arSelect['this'] = ' STRAIGHT_JOIN ' . $metadata->arSelect['this'];
122
                $metadata->arFrom['this'] .= "\n" .
123
                    'LEFT JOIN ' . dbMySQLConnector::$prefix . 'materialfield as _mf
124
                ON ' . dbMySQLConnector::$prefix . 'material.MaterialID = _mf.MaterialID';
125
                $metadata->arGroup[] = dbMySQLConnector::$prefix . 'material.MaterialID';
126
127
                // Iterate entity fields
128
                foreach ($this->navigationFields($structureRow['StructureID']) as $fieldID => $fieldRow) {
129
                    // Get camelCase and transliterated field name
130
                    $fieldName = $this->fieldName($fieldRow['Name']);
131
132
                    // Store field metadata
133
                    $metadata->realNames[$fieldRow['Name']] = $fieldName;
134
                    $metadata->allFieldIDs[$fieldID] = $fieldName;
135
                    $metadata->allFieldNames[$fieldName] = $fieldID;
136
                    $metadata->allFieldValueColumns[$fieldID] = Field::valueColumn($fieldRow[Field::F_TYPE]);
137
                    $metadata->allFieldTypes[$fieldID] = Field::phpType($fieldRow['Type']);
138
                    $metadata->allFieldCmsTypes[$fieldID] = $fieldRow['Type'];
139
                    $metadata->fieldDescriptions[$fieldID] = $fieldRow['Description'] . ', ' . $fieldRow['Name'] . '#' . $fieldID;
140
                    $metadata->fieldRawDescriptions[$fieldID] = $fieldRow['Description'];
141
142
                    // Fill localization fields collections
143
                    if ($fieldRow[Field::F_LOCALIZED] === 1) {
144
                        $metadata->localizedFieldIDs[$fieldID] = $fieldName;
145
                    } else {
146
                        $metadata->notLocalizedFieldIDs[$fieldID] = $fieldName;
147
                    }
148
149
                    // Fill all fields which should display in list
150
                    if ($fieldRow['showInList'] == 1) {
151
                        $metadata->showFieldsInList[] = $fieldID;
152
                    }
153
154
                    // Set old AR collections of metadata
155
                    $metadata->arAttributes[$fieldName] = $fieldName;
156
                    $metadata->arMap[$fieldName] = dbMySQLConnector::$prefix . 'material.' . $fieldName;
157
158
                    // Add additional field column to entity query
159
                    $equal = '((_mf.FieldID = ' . $fieldID . ')&&(_mf.locale ' . ($fieldRow['local'] ? ' = "@locale"' : 'IS NULL') . '))';
160
                    $metadata->arSelect['this'] .= "\n\t\t" . ',MAX(IF(' . $equal . ', _mf.`' . Field::valueColumn($fieldRow['Type']) . '`, NULL)) as `' . $fieldName . '`';
161
                }
162
163
                // Get id of child navigation
164
                foreach ($this->entityChildNavigation($structureRow['StructureID']) as $childNavigation) {
165
                    $metadata->childNavigationIDs[] = $childNavigation['StructureID'];
166
                }
167
168
                // Store metadata by entity identifier
169
                $this->metadata[$structureRow['StructureID']] = $metadata;
170
            }
171
        }
172
    }
173
174
    /**
175
     * Transliterate string to english.
176
     *
177
     * @param string $string Source string
178
     * @return string Transliterated string
179
     */
180
    protected function transliterated($string)
181
    {
182
        return str_replace(
183
            ' ',
184
            '',
185
            ucwords(iconv("UTF-8", "UTF-8//IGNORE", strtr($string, array(
186
                            "'" => "",
187
                            "`" => "",
188
                            "-" => " ",
189
                            "_" => " ",
190
                            "а" => "a", "А" => "a",
191
                            "б" => "b", "Б" => "b",
192
                            "в" => "v", "В" => "v",
193
                            "г" => "g", "Г" => "g",
194
                            "д" => "d", "Д" => "d",
195
                            "е" => "e", "Е" => "e",
196
                            "ж" => "zh", "Ж" => "zh",
197
                            "з" => "z", "З" => "z",
198
                            "и" => "i", "И" => "i",
199
                            "й" => "y", "Й" => "y",
200
                            "к" => "k", "К" => "k",
201
                            "л" => "l", "Л" => "l",
202
                            "м" => "m", "М" => "m",
203
                            "н" => "n", "Н" => "n",
204
                            "о" => "o", "О" => "o",
205
                            "п" => "p", "П" => "p",
206
                            "р" => "r", "Р" => "r",
207
                            "с" => "s", "С" => "s",
208
                            "т" => "t", "Т" => "t",
209
                            "у" => "u", "У" => "u",
210
                            "ф" => "f", "Ф" => "f",
211
                            "х" => "h", "Х" => "h",
212
                            "ц" => "c", "Ц" => "c",
213
                            "ч" => "ch", "Ч" => "ch",
214
                            "ш" => "sh", "Ш" => "sh",
215
                            "щ" => "sch", "Щ" => "sch",
216
                            "ъ" => "", "Ъ" => "",
217
                            "ы" => "y", "Ы" => "y",
218
                            "ь" => "", "Ь" => "",
219
                            "э" => "e", "Э" => "e",
220
                            "ю" => "yu", "Ю" => "yu",
221
                            "я" => "ya", "Я" => "ya",
222
                            "і" => "i", "І" => "i",
223
                            "ї" => "yi", "Ї" => "yi",
224
                            "є" => "e", "Є" => "e"
225
                        )
226
                    )
227
                )
228
            )
229
        );
230
    }
231
232
    /**
233
     * Get class constant name by its value.
234
     *
235
     * @param string $value Constant value
236
     * @param string $className Class name
237
     * @return string Full constant name
238
     */
239
    protected function constantNameByValue($value, $className = Field::ENTITY)
240
    {
241
        // Get array where class constants are values and their values are keys
242
        $nameByValue = array_flip((new \ReflectionClass($className))->getConstants());
243
244
        // Try to find constant by its value
245
        if (null !== $nameByValue[$value]) {
246
            // Return constant name
247
            return $nameByValue[$value];
248
        }
249
250
        return '';
251
    }
252
253
    /**
254
     * Get correct entity name.
255
     *
256
     * @param string $navigationName Original navigation entity name
257
     * @return string Correct PHP-supported entity name
258
     */
259
    protected function entityName($navigationName)
260
    {
261
        return ucfirst($this->getValidName($this->transliterated($navigationName)));
262
    }
263
264
    /**
265
     * Remove all wrong characters from entity name
266
     *
267
     * @param string $navigationName Original navigation entity name
268
     * @return string Correct PHP-supported entity name
269
     */
270
    protected function getValidName($navigationName)
271
    {
272
        return preg_replace('/(^\d*)|([^\w\d_])/', '', $navigationName);
273
    }
274
275
    /**
276
     * Get correct full entity name with name space.
277
     *
278
     * @param string $navigationName Original navigation entity name
279
     * @param string $namespace Namespace
280
     * @return string Correct PHP-supported entity name
281
     */
282
    protected function fullEntityName($navigationName, $namespace = __NAMESPACE__)
283
    {
284
        return '\\'.$namespace.'\\'.$this->entityName($navigationName);
285
    }
286
287
    /**
288
     * Get correct field name.
289
     *
290
     * @param string $fieldName Original field name
291
     * @return string Correct PHP-supported field name
292
     */
293
    protected function fieldName($fieldName)
294
    {
295
        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...
296
    }
297
298
    /**
299
     * Get additional field type in form of Field constant name
300
     * by database additional field type identifier.
301
     *
302
     * @param integer $fieldType Additional field type identifier
303
     * @return string Additional field type constant
304
     */
305
    protected function additionalFieldType($fieldType)
306
    {
307
        return 'Field::'.$this->constantNameByValue($fieldType);
308
    }
309
310
311
    /** @return string Entity state hash */
312
    public function entityHash()
313
    {
314
        // Получим информацию о всех таблицах из БД
315
        return md5(serialize($this->database->fetch(
316
            'SELECT `TABLES`.`TABLE_NAME` as `TABLE_NAME`
317
              FROM `information_schema`.`TABLES` as `TABLES`
318
              WHERE `TABLES`.`TABLE_SCHEMA`="' . $this->database->database() . '";'
319
        )));
320
    }
321
322
    /**
323
     * Find entity parent.
324
     *
325
     * @param $entityID
326
     *
327
     * @return null|int Parent entity identifier
328
     */
329
    public function entityParent($entityID)
330
    {
331
        $parentData = $this->database->fetch('
332
SELECT *
333
FROM structure_relation as sm
334
JOIN structure as s ON s.StructureID = sm.parent_id
335
WHERE sm.child_id = "' . $entityID . '"
336
AND s.StructureID != "' . $entityID . '"
337
');
338
339
        // Get parent entity identifier
340
        return count($parentData) ? $parentData[0]['StructureID'] : null;
341
    }
342
343
    /** @return array Get collection of navigation objects */
344
    protected function entityNavigations($type = 0)
345
    {
346
        return $this->database->fetch('
347
        SELECT * FROM `structure`
348
        WHERE `Active` = "1" AND `Type` = "'.$type.'"
349
        ORDER BY `ParentID` ASC
350
        ');
351
    }
352
353
    /** @return array Get collection of child navigation objects */
354
    protected function entityChildNavigation($parentId)
355
    {
356
        return $this->database->fetch('
357
        SELECT * FROM `structure`
358
        WHERE `Active` = "1" AND `ParentID` = ' . $parentId . '
359
        ORDER BY `ParentID` ASC
360
        ');
361
    }
362
363
    /** @return array Collection of navigation additional fields */
364
    protected function navigationFields($navigationID)
365
    {
366
        $return = array();
367
        // TODO: Optimize queries make one single query with only needed data
368
        foreach ($this->database->fetch('SELECT * FROM `structurefield` WHERE `StructureID` = "' . $navigationID . '" AND `Active` = "1"') as $fieldStructureRow) {
369
            foreach ($this->database->fetch('SELECT * FROM `field` WHERE `FieldID` = "' . $fieldStructureRow['FieldID'] . '"') as $fieldRow) {
370
                $return[$fieldRow['FieldID']] = $fieldRow;
371
            }
372
        }
373
374
        return $return;
375
    }
376
}
377