Issues (187)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

gii/baseUserModel/Generator.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link http://vistart.name/
9
 * @copyright Copyright (c) 2015 vistart
10
 * @license http://vistart.name/license/
11
 */
12
13
namespace vistart\Models\gii\baseUserModel;
14
15
use Yii;
16
use yii\db\ActiveQuery;
17
use yii\db\ActiveRecord;
18
use yii\db\Connection;
19
use yii\db\Schema;
20
use yii\gii\CodeFile;
21
use yii\helpers\Inflector;
22
use yii\base\NotSupportedException;
23
use vistart\Models\models\BaseUserModel;
24
25
/**
26
 * Description of Generator
27
 *
28
 * @author vistart <[email protected]>
29
 */
30
class Generator extends \yii\gii\Generator {
31
32
    public $db = 'db';
33
    public $guidAttribute = 'guid';
34
    public $idAttribute = 'id';
35
    public $idAttributeType = '';
36
    public $idAttributeTypes = [
37
        0 => 'Random Number',
38
        1 => 'Random String',
39
        2 => 'Auto Increment',
40
    ];
41
    public $passwordHashAttribute = 'pass_hash';
42
    public $createdAtAttribute = 'create_time';
43
    public $updatedAtAttribute = 'update_time';
44
    public $enableIP = true;
45
    public $ipAttribute1 = 'ip_1';
46
    public $ipAttribute2 = 'ip_2';
47
    public $ipAttribute3 = 'ip_3';
48
    public $ipAttribute4 = 'ip_4';
49
    public $ipTypeAttribute = 'ip_type';
50
    public $authKeyAttribute = 'auth_key';
51
    public $accessTokenAttribute = 'access_token';
52
    public $passwordResetTokenAttribute = 'password_reset_token';
53
    public $statusAttribute = 'status';
54
    public $sourceAttribute = 'source';
55
    public $ns = 'app\models';
56
    public $tableName;
57
    public $modelClass;
58
    public $baseClass = 'vistart\Models\models\BaseUserModel';
59
    public $generatePresettingRules = false;
60
    public $generatePresettingBehaviors = false;
61
    public $generateRelations = true;
62
    public $generateLabelsFromComments = false;
63
    public $useTablePrefix = false;
64
    public $useSchemaName = true;
65
    public $generateQuery = false;
66
    public $queryNs = 'app\models';
67
    public $queryClass;
68
    public $queryBaseClass = 'yii\db\ActiveQuery';
69
70
    /**
71
     * @inheritdoc
72
     */
73
    public function getName() {
74
        return 'User Model Generator';
75
    }
76
77
    /**
78
     * @inheritdoc
79
     */
80
    public function getDescription() {
81
        return 'This generator generates an BaseUserModel class for the specified database table.';
82
    }
83
84
    /**
85
     * @inheritdoc
86
     */
87
    public function rules() {
88
        return array_merge(parent::rules(), [
89
            [['db', 'ns', 'tableName', 'guidAttribute', 'idAttribute', 'passwordHashAttribute', 'createdAtAttribute', 'updatedAtAttribute', 'ipAttribute1', 'ipAttribute2', 'ipAttribute3', 'ipAttribute4', 'ipTypeAttribute', 'authKeyAttribute', 'accessTokenAttribute', 'passwordResetTokenAttribute', 'statusAttribute', 'sourceAttribute', 'modelClass', 'baseClass', 'queryNs', 'queryClass', 'queryBaseClass'], 'filter', 'filter' => 'trim'],
90
            [['ns', 'queryNs'], 'filter', 'filter' => function($value) {
91
            return trim($value, '\\');
92
        }],
93
            [['db', 'ns', 'tableName', 'baseClass', 'queryNs', 'queryBaseClass', 'guidAttribute', 'passwordHashAttribute', 'authKeyAttribute', 'accessTokenAttribute', 'passwordResetTokenAttribute'], 'required'],
94
            [['db', 'modelClass', 'queryClass'], 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'],
95
            [['ns', 'baseClass', 'queryNs', 'queryBaseClass'], 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'],
96
            [['tableName'], 'match', 'pattern' => '/^(\w+\.)?([\w\*]+)$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'],
97
            [['db'], 'validateDb'],
98
            [['ns', 'queryNs'], 'validateNamespace'],
99
            [['tableName'], 'validateTableName'],
100
            [['modelClass'], 'validateModelClass', 'skipOnEmpty' => false],
101
            [['baseClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]],
102
            [['queryBaseClass'], 'validateClass', 'params' => ['extends' => ActiveQuery::className()]],
103
            [['enableIP', 'generatePresettingRules', 'generatePresettingBehaviors', 'generateRelations', 'generateLabelsFromComments', 'useTablePrefix', 'useSchemaName', 'generateQuery'], 'boolean'],
104
            [['guidAttribute', 'idAttribute', 'passwordHashAttribute', 'createdAtAttribute', 'updatedAtAttribute', 'ipAttribute1', 'ipAttribute2', 'ipAttribute3', 'ipAttribute4', 'ipTypeAttribute', 'authKeyAttribute', 'accessTokenAttribute', 'passwordResetTokenAttribute', 'statusAttribute', 'sourceAttribute'], 'validateFieldsExist'],
105
            [['enableIP', 'ipAttribute1', 'ipAttribute2', 'ipAttribute3', 'ipAttribute4', 'ipTypeAttribute'], 'validateIP'],
106
            [['enableI18N'], 'boolean'],
107
            [['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false],
108
        ]);
109
    }
110
111
    /**
112
     * @inheritdoc
113
     */
114
    public function attributeLabels() {
115
        return array_merge(parent::attributeLabels(), [
116
            'ns' => 'Namespace',
117
            'db' => 'Database Connection ID',
118
//            'guidAttribute' => 'guid',
119
//            'idAttribute' => 'id',
120
//            'passwordHashAttribute' => 'pass_hash',
121
//            'createdAtAttribute' => 'create_time',
122
//            'updatedAtAttribute' => 'update_time',
123
//            'enableIP' => 'enableIP',
124
//            'ipAttribute1' => 'ip_1',
125
//            'ipAttribute2' => 'ip_2',
126
//            'ipAttribute3' => 'ip_3',
127
//            'ipAttribute4' => 'ip_4',
128
//            'ipTypeAttribute' => 'ip_type',
129
//            'authKeyAttribute' => 'auth_key',
130
//            'accessTokenAttribute' => 'access_token',
131
//            'passwordResetTokenAttribute' => 'password_reset_token',
132
//            'statusAttribute' => 'status',
133
//            'sourceAttribute' => 'source',
134
            'tableName' => 'Table Name',
135
            'modelClass' => 'Model Class',
136
            'baseClass' => 'Base Class',
137
            'generatePresettingRules' => 'Generate Presetting Rules',
138
            'generatePresettingBehaviors' => 'Generate Presetting Behaviors',
139
            'generateRelations' => 'Generate Relations',
140
            'generateLabelsFromComments' => 'Generate Labels from DB Comments',
141
            'generateQuery' => 'Generate ActiveQuery',
142
            'queryNs' => 'ActiveQuery Namespace',
143
            'queryClass' => 'ActiveQuery Class',
144
            'queryBaseClass' => 'ActiveQuery Base Class',
145
        ]);
146
    }
147
148
    /**
149
     * @inheritdoc
150
     */
151
    public function hints() {
152
        return array_merge(parent::hints(), [
153
            'ns' => 'This is the namespace of the ActiveRecord class to be generated, e.g., <code>app\models</code>',
154
            'db' => 'This is the ID of the DB application component.',
155
            'tableName' => 'This is the name of the DB table that the new ActiveRecord class is associated with, e.g. <code>post</code>.
156
                The table name may consist of the DB schema part if needed, e.g. <code>public.post</code>.
157
                The table name may end with asterisk to match multiple table names, e.g. <code>tbl_*</code>
158
                will match tables who name starts with <code>tbl_</code>. In this case, multiple ActiveRecord classes
159
                will be generated, one for each matching table name; and the class names will be generated from
160
                the matching characters. For example, table <code>tbl_post</code> will generate <code>Post</code>
161
                class.',
162
            'modelClass' => 'This is the name of the ActiveRecord class to be generated. The class name should not contain
163
                the namespace part as it is specified in "Namespace". You do not need to specify the class name
164
                if "Table Name" ends with asterisk, in which case multiple ActiveRecord classes will be generated.',
165
            'baseClass' => 'This is the base class of the new ActiveRecord class. It should be a fully qualified namespaced class name.',
166
            'guidAttribute' => 'REQUIRED. GUID Attribute Name, as well as field name of user table.',
167
            'idAttribute' => 'OPTIONAL. ID Attribute Name, as well as field name of user table. Please left empty if no need for this feature.',
168
            'passwordHashAttribute' => 'REQUIRED. Password Hash Attribute Name, as well as field name of user table.',
169
            'createdAtAttribute' => 'OPTIONAL. Created At Attribute Name, as well as field name of user table. Please left empty if no need for this feature.',
170
            'updatedAtAttribute' => 'OPTIONAL. Updated At Attribute Name, as well as field name of user table. Please left empty if no need for this feature.',
171
            'enableIP' => 'Indicates whether enable the IP address feature. If true, the following five attributes are required.',
172
            'ipAttribute1' => 'IP Attribute 1 Name, as well as field name of user table.',
173
            'ipAttribute2' => 'IP Attribute 2 Name, as well as field name of user table.',
174
            'ipAttribute3' => 'IP Attribute 3 Name, as well as field name of user table.',
175
            'ipAttribute4' => 'IP Attribute 4 Name, as well as field name of user table.',
176
            'ipTypeAttribute' => 'IP Type Attribute Name, as well as field name of user table.',
177
            'authKeyAttribute' => 'REQUIRED. Auth Key Attribute Name, as well as field name of user table.',
178
            'accessTokenAttribute' => 'REQUIRED. Access Token Attribute Name, as well as field name of user table.',
179
            'passwordResetTokenAttribute' => 'OPTIONAL. Password Reset Token Attribute Name, as well as field name of user table. Please left empty if no need for this feature.',
180
            'sourceAttribute' => 'OPTIONAL. Source Attribute Name, as well as field name of user table. Please left empty if no need for this feature.',
181
            'statusAttribute' => 'OPTIONAL. Status Attribute Name, as well as field name of user table. Please left empty if no need for this feature.',
182
            'generatePresettingRules' => 'This indicates whether the generator should generate the presetting rules.',
183
            'generatePresettingBehaviors' => 'This indicates whether the generator should generate the presetting behaviors.',
184
            'generateRelations' => 'This indicates whether the generator should generate relations based on
185
                foreign key constraints it detects in the database. Note that if your database contains too many tables,
186
                you may want to uncheck this option to accelerate the code generation process.',
187
            'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels
188
                by using the comments of the corresponding DB columns.',
189
            'useTablePrefix' => 'This indicates whether the table name returned by the generated ActiveRecord class
190
                should consider the <code>tablePrefix</code> setting of the DB connection. For example, if the
191
                table name is <code>tbl_post</code> and <code>tablePrefix=tbl_</code>, the ActiveRecord class
192
                will return the table name as <code>{{%post}}</code>.',
193
            'useSchemaName' => 'This indicates whether to include the schema name in the ActiveRecord class
194
                when it\'s auto generated. Only non default schema would be used.',
195
            'generateQuery' => 'This indicates whether to generate ActiveQuery for the ActiveRecord class.',
196
            'queryNs' => 'This is the namespace of the ActiveQuery class to be generated, e.g., <code>app\models</code>',
197
            'queryClass' => 'This is the name of the ActiveQuery class to be generated. The class name should not contain
198
                the namespace part as it is specified in "ActiveQuery Namespace". You do not need to specify the class name
199
                if "Table Name" ends with asterisk, in which case multiple ActiveQuery classes will be generated.',
200
            'queryBaseClass' => 'This is the base class of the new ActiveQuery class. It should be a fully qualified namespaced class name.',
201
        ]);
202
    }
203
204
    /**
205
     * @inheritdoc
206
     */
207
    public function autoCompleteData() {
208
        $db = $this->getDbConnection();
209
        if ($db !== null) {
210
            return [
211
                'tableName' => function () use ($db) {
212
                    return $db->getSchema()->getTableNames();
213
                },
214
            ];
215
        } else {
216
            return [];
217
        }
218
    }
219
220
    /**
221
     * @inheritdoc
222
     */
223
    public function requiredTemplates() {
224
        // @todo make 'query.php' to be required before 2.1 release
225
        return ['model.php'/* , 'query.php' */];
226
    }
227
228
    /**
229
     * @inheritdoc
230
     */
231
    public function stickyAttributes() {
232
        return array_merge(parent::stickyAttributes(), ['ns', 'db', 'baseClass', 'generatePresettingRules', 'generatePresettingBehaviors', 'generateRelations', 'generateLabelsFromComments', 'useTablePrefix', 'queryNs', 'queryBaseClass']);
233
    }
234
235
    public function generate() {
236
        $files = [];
237
        $relations = $this->generateRelations();
238
        $db = $this->getDbConnection();
239
        foreach ($this->getTableNames() as $tableName) {
240
            // model :
241
            $modelClassName = $this->generateClassName($tableName);
242
            $queryClassName = ($this->generateQuery) ? $this->generateQueryClassName($modelClassName) : false;
243
            $tableSchema = $db->getTableSchema($tableName);
244
            $params = [
245
                'tableName' => $tableName,
246
                'className' => $modelClassName,
247
                'queryClassName' => $queryClassName,
248
                'tableSchema' => $tableSchema,
249
                'labels' => $this->generateLabels($tableSchema),
250
                'rules' => $this->generatePresettingRules,
251
                'behaviors' => $this->generatePresettingBehaviors,
252
                'relations' => isset($relations[$tableName]) ? $relations[$tableName] : [],
253
            ];
254
            $files[] = new CodeFile(
255
                    Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $modelClassName . '.php', $this->render('model.php', $params)
256
            );
257
258
            // query :
259
            if ($queryClassName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $queryClassName of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
260
                $params = [
261
                    'className' => $queryClassName,
262
                    'modelClassName' => $modelClassName,
263
                ];
264
                $files[] = new CodeFile(
265
                        Yii::getAlias('@' . str_replace('\\', '/', $this->queryNs)) . '/' . $queryClassName . '.php', $this->render('query.php', $params)
266
                );
267
            }
268
        }
269
        return $files;
270
    }
271
272
    /**
273
     * Generates the attribute labels for the specified table.
274
     * @param \yii\db\TableSchema $table the table schema
275
     * @return array the generated attribute labels (name => label)
276
     */
277
    public function generateLabels($table) {
278
        $labels = [];
279
        foreach ($table->columns as $column) {
280
            if ($this->generateLabelsFromComments && !empty($column->comment)) {
281
                $labels[$column->name] = $column->comment;
282
            } elseif (!strcasecmp($column->name, 'id')) {
283
                $labels[$column->name] = 'ID';
284
            } else {
285
                $label = Inflector::camel2words($column->name);
286
                if (!empty($label) && substr_compare($label, ' id', -3, 3, true) === 0) {
287
                    $label = substr($label, 0, -3) . ' ID';
288
                }
289
                $labels[$column->name] = $label;
290
            }
291
        }
292
293
        return $labels;
294
    }
295
    
296
    /**
297
     * Generates relations using a junction table by adding an extra viaTable().
298
     * @param \yii\db\TableSchema the table being checked
299
     * @param array $fks obtained from the checkPivotTable() method
300
     * @param array $relations
301
     * @return array modified $relations
302
     */
303
    private function generateManyManyRelations($table, $fks, $relations) {
304
        $db = $this->getDbConnection();
305
        $table0 = $fks[$table->primaryKey[0]][0];
306
        $table1 = $fks[$table->primaryKey[1]][0];
307
        $className0 = $this->generateClassName($table0);
308
        $className1 = $this->generateClassName($table1);
309
        $table0Schema = $db->getTableSchema($table0);
310
        $table1Schema = $db->getTableSchema($table1);
311
312
        $link = $this->generateRelationLink([$fks[$table->primaryKey[1]][1] => $table->primaryKey[1]]);
313
        $viaLink = $this->generateRelationLink([$table->primaryKey[0] => $fks[$table->primaryKey[0]][1]]);
314
        $relationName = $this->generateRelationName($relations, $table0Schema, $table->primaryKey[1], true);
315
        $relations[$table0Schema->fullName][$relationName] = [
316
            "return \$this->hasMany($className1::className(), $link)->viaTable('"
317
            . $this->generateTableName($table->name) . "', $viaLink);",
318
            $className1,
319
            true,
320
        ];
321
322
        $link = $this->generateRelationLink([$fks[$table->primaryKey[0]][1] => $table->primaryKey[0]]);
323
        $viaLink = $this->generateRelationLink([$table->primaryKey[1] => $fks[$table->primaryKey[1]][1]]);
324
        $relationName = $this->generateRelationName($relations, $table1Schema, $table->primaryKey[0], true);
325
        $relations[$table1Schema->fullName][$relationName] = [
326
            "return \$this->hasMany($className0::className(), $link)->viaTable('"
327
            . $this->generateTableName($table->name) . "', $viaLink);",
328
            $className0,
329
            true,
330
        ];
331
332
        return $relations;
333
    }
334
335
    /**
336
     * @return array the generated relation declarations
337
     */
338
    protected function generateRelations() {
339
        if (!$this->generateRelations) {
340
            return [];
341
        }
342
343
        $db = $this->getDbConnection();
344
345
        $schema = $db->getSchema();
346
        if ($schema->hasMethod('getSchemaNames')) { // keep BC to Yii versions < 2.0.4
347
            try {
348
                $schemaNames = $schema->getSchemaNames();
349
            } catch (NotSupportedException $e) {
350
                // schema names are not supported by schema
351
            }
352
        }
353
        if (!isset($schemaNames)) {
354
            if (($pos = strpos($this->tableName, '.')) !== false) {
355
                $schemaNames = [substr($this->tableName, 0, $pos)];
356
            } else {
357
                $schemaNames = [''];
358
            }
359
        }
360
361
        $relations = [];
362
        foreach ($schemaNames as $schemaName) {
363
            foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) {
364
                $className = $this->generateClassName($table->fullName);
365
                foreach ($table->foreignKeys as $refs) {
366
                    $refTable = $refs[0];
367
                    $refTableSchema = $db->getTableSchema($refTable);
368
                    unset($refs[0]);
369
                    $fks = array_keys($refs);
370
                    $refClassName = $this->generateClassName($refTable);
371
372
                    // Add relation for this table
373
                    $link = $this->generateRelationLink(array_flip($refs));
374
                    $relationName = $this->generateRelationName($relations, $table, $fks[0], false);
375
                    $relations[$table->fullName][$relationName] = [
376
                        "return \$this->hasOne($refClassName::className(), $link);",
377
                        $refClassName,
378
                        false,
379
                    ];
380
381
                    // Add relation for the referenced table
382
                    $uniqueKeys = [$table->primaryKey];
383
                    try {
384
                        $uniqueKeys = array_merge($uniqueKeys, $db->getSchema()->findUniqueIndexes($table));
385
                    } catch (NotSupportedException $e) {
386
                        // ignore
387
                    }
388
                    $hasMany = true;
389
                    foreach ($uniqueKeys as $uniqueKey) {
390
                        if (count(array_diff(array_merge($uniqueKey, $fks), array_intersect($uniqueKey, $fks))) === 0) {
391
                            $hasMany = false;
392
                            break;
393
                        }
394
                    }
395
                    $link = $this->generateRelationLink($refs);
396
                    $relationName = $this->generateRelationName($relations, $refTableSchema, $className, $hasMany);
397
                    $relations[$refTableSchema->fullName][$relationName] = [
398
                        "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "($className::className(), $link);",
399
                        $className,
400
                        $hasMany,
401
                    ];
402
                }
403
404
                if (($fks = $this->checkPivotTable($table)) === false) {
405
                    continue;
406
                }
407
408
                $relations = $this->generateManyManyRelations($table, $fks, $relations);
409
            }
410
        }
411
412
        return $relations;
413
    }
414
415
    /**
416
     * Generates the link parameter to be used in generating the relation declaration.
417
     * @param array $refs reference constraint
418
     * @return string the generated link parameter.
419
     */
420
    protected function generateRelationLink($refs) {
421
        $pairs = [];
422
        foreach ($refs as $a => $b) {
423
            $pairs[] = "'$a' => '$b'";
424
        }
425
426
        return '[' . implode(', ', $pairs) . ']';
427
    }
428
    
429
    protected function generateRules($table) {
430
        
431
    }
432
433
    /**
434
     * Checks if the given table is a junction table.
435
     * For simplicity, this method only deals with the case where the pivot contains two PK columns,
436
     * each referencing a column in a different table.
437
     * @param \yii\db\TableSchema the table being checked
438
     * @return array|boolean the relevant foreign key constraint information if the table is a junction table,
439
     * or false if the table is not a junction table.
440
     */
441
    protected function checkPivotTable($table) {
442
        $pk = $table->primaryKey;
443
        if (count($pk) !== 2) {
444
            return false;
445
        }
446
        $fks = [];
447
        foreach ($table->foreignKeys as $refs) {
448
            if (count($refs) === 2) {
449
                if (isset($refs[$pk[0]])) {
450
                    $fks[$pk[0]] = [$refs[0], $refs[$pk[0]]];
451
                } elseif (isset($refs[$pk[1]])) {
452
                    $fks[$pk[1]] = [$refs[0], $refs[$pk[1]]];
453
                }
454
            }
455
        }
456
        if (count($fks) === 2 && $fks[$pk[0]][0] !== $fks[$pk[1]][0]) {
457
            return $fks;
458
        } else {
459
            return false;
460
        }
461
    }
462
463
    /**
464
     * Generate a relation name for the specified table and a base name.
465
     * @param array $relations the relations being generated currently.
466
     * @param \yii\db\TableSchema $table the table schema
467
     * @param string $key a base name that the relation name may be generated from
468
     * @param boolean $multiple whether this is a has-many relation
469
     * @return string the relation name
470
     */
471
    protected function generateRelationName($relations, $table, $key, $multiple) {
472
        if (!empty($key) && substr_compare($key, 'id', -2, 2, true) === 0 && strcasecmp($key, 'id')) {
473
            $key = rtrim(substr($key, 0, -2), '_');
474
        }
475
        if ($multiple) {
476
            $key = Inflector::pluralize($key);
477
        }
478
        $name = $rawName = Inflector::id2camel($key, '_');
479
        $i = 0;
480
        while (isset($table->columns[lcfirst($name)])) {
481
            $name = $rawName . ($i++);
482
        }
483
        while (isset($relations[$table->fullName][$name])) {
484
            $name = $rawName . ($i++);
485
        }
486
487
        return $name;
488
    }
489
    
490
    public function validateFieldsExist() {
491
        $db = $this->getDbConnection();
492
        foreach ($this->getTableNames() as $table) {
493
            $tableSchema = $db->getTableSchema($table);
494
            $fields = [
495
                'guidAttribute',
496
                'idAttribute',
497
                'passwordHashAttribute',
498
                'createdAtAttribute',
499
                'updatedAtAttribute',
500
                'ipAttribute1',
501
                'ipAttribute2',
502
                'ipAttribute3',
503
                'ipAttribute4',
504
                'ipTypeAttribute',
505
                'authKeyAttribute',
506
                'accessTokenAttribute',
507
                'passwordResetTokenAttribute',
508
                'statusAttribute',
509
                'sourceAttribute',
510
            ];
511
            foreach ($fields as $field) {
512
                if (isset($this->$field) && $this->$field != '' && !isset($tableSchema->columns[$this->$field])) {
513
                    $this->addError($field, '`' . $this->$field . '` field does not exist in `' . $table . '` table.');
514
                    continue;
515
                }
516
            }
517
        }
518
    }
519
520
    /**
521
     * Validates the [[db]] attribute.
522
     */
523
    public function validateDb() {
524
        if (!Yii::$app->has($this->db)) {
525
            $this->addError('db', 'There is no application component named "db".');
526
        } elseif (!Yii::$app->get($this->db) instanceof Connection) {
527
            $this->addError('db', 'The "db" application component must be a DB connection instance.');
528
        }
529
    }
530
    
531
    public function validateIP() {
532
        if (!$this->enableIP) {
533
            return;
534
        }
535
        $db = $this->getDbConnection();
0 ignored issues
show
$db 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...
536
        $ipAttribute = 'ipAttribute';
537
        for ($i = 1; $i <= 4; $i++) {
538
            $ipAttributeName = $ipAttribute . $i;
539
            if (empty($this->$ipAttributeName)) {
540
                $this->addError($ipAttributeName, "`$ipAttributeName` should not be empty.");
541
                continue;
542
            }
543
        }
544
        if (empty($this->ipTypeAttribute)) {
545
            $this->addError('ipTypeAttribute', "`ipTypeAttribute` should not be empty.");
546
            return;
547
        }
548
    }
549
550
    /**
551
     * Validates the [[ns]] attribute.
552
     */
553
    public function validateNamespace() {
554
        $this->ns = ltrim($this->ns, '\\');
555
        $path = Yii::getAlias('@' . str_replace('\\', '/', $this->ns), false);
556
        if ($path === false) {
557
            $this->addError('ns', 'Namespace must be associated with an existing directory.');
558
        }
559
    }
560
561
    /**
562
     * Validates the [[modelClass]] attribute.
563
     */
564
    public function validateModelClass() {
565
        if ($this->isReservedKeyword($this->modelClass)) {
566
            $this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.');
567
        }
568
        if ((empty($this->tableName) || substr_compare($this->tableName, '*', -1, 1)) && $this->modelClass == '') {
569
            $this->addError('modelClass', 'Model Class cannot be blank if table name does not end with asterisk.');
570
        }
571
    }
572
573
    /**
574
     * Validates the [[tableName]] attribute.
575
     */
576
    public function validateTableName() {
577
        if (strpos($this->tableName, '*') !== false && substr_compare($this->tableName, '*', -1, 1)) {
578
            $this->addError('tableName', 'Asterisk is only allowed as the last character.');
579
580
            return;
581
        }
582
        $tables = $this->getTableNames();
583
        if (empty($tables)) {
584
            $this->addError('tableName', "Table '{$this->tableName}' does not exist.");
585
        } else {
586
            foreach ($tables as $table) {
587
                $class = $this->generateClassName($table);
588
                if ($this->isReservedKeyword($class)) {
589
                    $this->addError('tableName', "Table '$table' will generate a class which is a reserved PHP keyword.");
590
                    break;
591
                }
592
            }
593
        }
594
    }
595
596
    protected $tableNames;
597
    protected $classNames;
598
599
    /**
600
     * @return array the table names that match the pattern specified by [[tableName]].
601
     */
602
    protected function getTableNames() {
603
        if ($this->tableNames !== null) {
604
            return $this->tableNames;
605
        }
606
        $db = $this->getDbConnection();
607
        if ($db === null) {
608
            return [];
609
        }
610
        $tableNames = [];
611
        if (strpos($this->tableName, '*') !== false) {
612
            if (($pos = strrpos($this->tableName, '.')) !== false) {
613
                $schema = substr($this->tableName, 0, $pos);
614
                $pattern = '/^' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '$/';
615
            } else {
616
                $schema = '';
617
                $pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/';
618
            }
619
620
            foreach ($db->schema->getTableNames($schema) as $table) {
621
                if (preg_match($pattern, $table)) {
622
                    $tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
623
                }
624
            }
625
        } elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
626
            $tableNames[] = $this->tableName;
627
            $this->classNames[$this->tableName] = $this->modelClass;
628
        }
629
630
        return $this->tableNames = $tableNames;
631
    }
632
633
    /**
634
     * Generates the table name by considering table prefix.
635
     * If [[useTablePrefix]] is false, the table name will be returned without change.
636
     * @param string $tableName the table name (which may contain schema prefix)
637
     * @return string the generated table name
638
     */
639
    public function generateTableName($tableName) {
640
        if (!$this->useTablePrefix) {
641
            return $tableName;
642
        }
643
644
        $db = $this->getDbConnection();
645
        if (preg_match("/^{$db->tablePrefix}(.*?)$/", $tableName, $matches)) {
646
            $tableName = '{{%' . $matches[1] . '}}';
647
        } elseif (preg_match("/^(.*?){$db->tablePrefix}$/", $tableName, $matches)) {
648
            $tableName = '{{' . $matches[1] . '%}}';
649
        }
650
        return $tableName;
651
    }
652
653
    /**
654
     * Generates a class name from the specified table name.
655
     * @param string $tableName the table name (which may contain schema prefix)
656
     * @param boolean $useSchemaName should schema name be included in the class name, if present
657
     * @return string the generated class name
658
     */
659
    protected function generateClassName($tableName, $useSchemaName = null) {
660
        if (isset($this->classNames[$tableName])) {
661
            return $this->classNames[$tableName];
662
        }
663
664
        $schemaName = '';
665
        $fullTableName = $tableName;
666
        if (($pos = strrpos($tableName, '.')) !== false) {
667
            if (($useSchemaName === null && $this->useSchemaName) || $useSchemaName) {
668
                $schemaName = substr($tableName, 0, $pos) . '_';
669
            }
670
            $tableName = substr($tableName, $pos + 1);
671
        }
672
673
        $db = $this->getDbConnection();
674
        $patterns = [];
675
        $patterns[] = "/^{$db->tablePrefix}(.*?)$/";
676
        $patterns[] = "/^(.*?){$db->tablePrefix}$/";
677
        if (strpos($this->tableName, '*') !== false) {
678
            $pattern = $this->tableName;
679
            if (($pos = strrpos($pattern, '.')) !== false) {
680
                $pattern = substr($pattern, $pos + 1);
681
            }
682
            $patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/';
683
        }
684
        $className = $tableName;
685
        foreach ($patterns as $pattern) {
686
            if (preg_match($pattern, $tableName, $matches)) {
687
                $className = $matches[1];
688
                break;
689
            }
690
        }
691
692
        return $this->classNames[$fullTableName] = Inflector::id2camel($schemaName . $className, '_');
693
    }
694
695
    /**
696
     * Generates a query class name from the specified model class name.
697
     * @param string $modelClassName model class name
698
     * @return string generated class name
699
     */
700
    protected function generateQueryClassName($modelClassName) {
701
        $queryClassName = $this->queryClass;
702
        if (empty($queryClassName) || strpos($this->tableName, '*') !== false) {
703
            $queryClassName = $modelClassName . 'Query';
704
        }
705
        return $queryClassName;
706
    }
707
708
    /**
709
     * @return Connection the DB connection as specified by [[db]].
710
     */
711
    protected function getDbConnection() {
712
        return Yii::$app->get($this->db, false);
713
    }
714
715
    /**
716
     * Checks if any of the specified columns is auto incremental.
717
     * @param \yii\db\TableSchema $table the table schema
718
     * @param array $columns columns to check for autoIncrement property
719
     * @return boolean whether any of the specified columns is auto incremental.
720
     */
721
    protected function isColumnAutoIncremental($table, $columns) {
722
        foreach ($columns as $column) {
723
            if (isset($table->columns[$column]) && $table->columns[$column]->autoIncrement) {
724
                return true;
725
            }
726
        }
727
728
        return false;
729
    }
730
731
}
732