Passed
Push — master ( 2d1a2e...608ac1 )
by Vitaly
49s
created

dbMySQL   D

Complexity

Total Complexity 91

Size/Duplication

Total Lines 754
Duplicated Lines 2.39 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 49
Bugs 15 Features 16
Metric Value
wmc 91
c 49
b 15
f 16
lcom 2
cbo 5
dl 18
loc 754
rs 4.4444

20 Methods

Rating   Name   Duplication   Size   Complexity  
A find_by_id() 0 22 2
A simple_query() 0 4 1
A debug() 0 8 2
B createField() 0 29 4
B __get_table_data() 0 46 2
A create() 0 12 1
A update() 0 9 1
A delete() 0 6 1
B find() 0 26 4
A protectQueryValue() 0 13 2
C getQueryFields() 0 32 7
B migration() 0 38 6
B profiler() 0 24 3
A innerCount() 0 13 1
C prepareSQL() 6 73 12
C prepareInnerSQL() 12 37 8
B getConditions() 0 24 4
C parseCondition() 0 42 11
C createObject() 0 42 7
C toRecords() 0 145 12

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like dbMySQL often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use dbMySQL, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace samson\activerecord;
3
4
use samsonframework\orm\QueryInterface;
5
use samsonframework\orm\ConditionInterface;
6
7
/**
8
 * Класс описывающий работу с MySQL
9
 * @author Vitaly Iegorov <[email protected]>
10
 * @author Nikita Kotenko <[email protected]>
11
 *
12
 */
13
class dbMySQL extends dbMySQLConnector
0 ignored issues
show
Coding Style introduced by
This class is not in CamelCase format.

Classes in PHP are usually named in CamelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. The whole name starts with a capital letter as well.

Thus the name database provider becomes DatabaseProvider.

Loading history...
14
{
15
    /**
16
     * Количество запросов класса
17
     * @var integer
18
     */
19
    private $query_count = 0;
20
21
    /** Show hide query debug information */
22
    public function debug($flag = true)
23
    {
24
        if ($flag) {
25
            $_SESSION['__AR_SHOW_QUERY__'] = true;
26
        } else {
27
            unset($_SESSION['__AR_SHOW_QUERY__']);
28
        }
29
    }
30
31
    /**
32
     * Check object $field field value as $table column
33
     * and if database table does not have it - create.
34
     * $field is not set in object - error returns
35
     *
36
     * @param object $object Pointer to object to get field names data
37
     * @param string $table Database table name
38
     * @param string $field Object field name
39
     * @param string $type Database column name
40
     *
41
     * @return bool True if database table has field or field has been created
42
     */
43
    public function createField($object, $table, $field, $type = 'INT')
44
    {
45
        // Check if db identifier field is configured
46
        if (class_exists($table)) {
47
            if (strlen($object->$field)) {
48
                // Variable to get all social table attributes
49
                $attributes = array();
50
                // Get table attributes - PHP 5.2 compatible
51
                eval('$attributes = ' . $table . '::$_attributes;');
52
53
                // Remove namespaces
54
                $table = \samson\core\AutoLoader::getOnlyClass($table);
55
56
                // Make keys lowercase
57
                $attributes = array_change_key_case_unicode($attributes);
58
59
                // If table does not have defined identifier field
60
                if (!isset($attributes[strtolower($object->$field)])) {
61
                    // Add identifier field to social users table
62
                    $this->simple_query('ALTER TABLE  `' . $table . '` ADD  `' . $object->$field . '` ' . $type . ' ');
0 ignored issues
show
Deprecated Code introduced by
The method samson\activerecord\dbMySQL::simple_query() has been deprecated with message: Use execute()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
63
                }
64
65
                return true;
66
67
            } else { // Signal error
68
                return e('Cannot load "' . get_class($object) . '" module - no $' . $field . ' is configured');
0 ignored issues
show
Deprecated Code introduced by
The function e() has been deprecated with message: Use custom exceptions

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
69
            }
70
        }
71
    }
72
73
    // TODO: Очень узкое место для совместимости с 5.2 !!!
74
    /**
75
     * Обратная совместить с PHP < 5.3 т.к. там нельзя подставлять переменное имя класса
76
     * в статическом контексте
77
     * @param unknown_type $class_name
78
     */
79
    public function __get_table_data($class_name)
0 ignored issues
show
Coding Style introduced by
Method name "dbMySQL::__get_table_data" is not in camel caps format
Loading history...
80
    {
81
        // Remove table prefix
82
        $class_name = str_replace(self::$prefix, '', $class_name);
83
84
        // Сформируем правильное имя класса
85
        $class_name = strpos($class_name, '\\') !== false ? $class_name : '\samson\activerecord\\'.$class_name;
86
87
        // Сформируем комманды на получение статических переменных определенного класса
88
        $_table_name = '$_table_name = ' . $class_name . '::$_table_name;';
89
        $_own_group = '$_own_group = ' . $class_name . '::$_own_group;';
90
        $_table_attributes = '$_table_attributes = ' . $class_name . '::$_table_attributes;';
91
        $_primary = '$_primary = ' . $class_name . '::$_primary;';
92
        $_sql_from = '$_sql_from = ' . $class_name . '::$_sql_from;';
93
        $_sql_select = '$_sql_select = ' . $class_name . '::$_sql_select;';
94
        $_attributes = '$_attributes = ' . $class_name . '::$_attributes;';
95
        $_types = '$_types = ' . $class_name . '::$_types;';
96
        $_map = '$_map = ' . $class_name . '::$_map;';
97
        $_relations = '$_relations = ' . $class_name . '::$_relations;';
98
        $_unique = '$_unique = ' . $class_name . '::$_unique;';
99
        $_relation_type = '$_relation_type = ' . $class_name . '::$_relation_type;';
100
        $_relation_alias = '$_relation_alias = ' . $class_name . '::$_relation_alias;';
101
102
        //trace($_table_name.$_primary.$_sql_from.$_sql_select.$_map.$_attributes.$_relations.$_relation_type.$_types.$_unique);
103
104
        // Выполним специальный код получения значений переменной
105
        eval($_own_group . $_table_name . $_primary . $_sql_from . $_sql_select . $_map . $_attributes . $_relations . $_relation_type . $_relation_alias . $_types . $_unique . $_table_attributes);
106
107
        // Вернем массив имен переменных и их значений
108
        return array
109
        (
110
            '_table_name' => $_table_name,
111
            '_own_group' => $_own_group,
112
            '_primary' => $_primary,
113
            '_attributes' => $_attributes,
114
            '_table_attributes' => $_table_attributes,
115
            '_types' => $_types,
116
            '_map' => $_map,
117
            '_relations' => $_relations,
118
            '_relation_type' => $_relation_type,
119
            '_relation_alias' => $_relation_alias,
120
            '_sql_from' => $_sql_from,
121
            '_sql_select' => $_sql_select,
122
            '_unique' => $_unique,
123
        );
124
    }
125
126
    public function create($className, &$object = null)
127
    {
128
        // ??
129
        $fields = $this->getQueryFields($className, $object);
130
        // Build SQL query
131
        $sql = 'INSERT INTO `' . $className::$_table_name . '` (`'
132
            . implode('`,`', array_keys($fields)) . '`)
133
            VALUES (' . implode(',', $fields) . ')';
134
        $this->query($sql);
0 ignored issues
show
Deprecated Code introduced by
The method samsonframework\orm\Database::query() has been deprecated with message: Use execute()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
135
        // Return last inserted row identifier
136
        return $this->driver->lastInsertId();
137
    }
138
139
    public function update($className, &$object)
140
    {
141
        // ??
142
        $fields = $this->getQueryFields($className, $object, true);
143
        // Build SQL query
144
        $sql = 'UPDATE `' . $className::$_table_name . '` SET ' . implode(',',
145
                $fields) . ' WHERE ' . $className::$_table_name . '.' . $className::$_primary . '="' . $object->id . '"';
146
        $this->query($sql);
0 ignored issues
show
Deprecated Code introduced by
The method samsonframework\orm\Database::query() has been deprecated with message: Use execute()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
147
    }
148
149
    public function delete($className, &$object)
150
    {
151
        // Build SQL query
152
        $sql = 'DELETE FROM `' . $className::$_table_name . '` WHERE ' . $className::$_primary . ' = "' . $object->id . '"';
153
        $this->query($sql);
0 ignored issues
show
Deprecated Code introduced by
The method samsonframework\orm\Database::query() has been deprecated with message: Use execute()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
154
    }
155
156
    /**
157
     * @see idb::find()
158
     */
159
    public function &find($class_name, QueryInterface $query)
160
    {
161
        // Результат выполнения запроса
162
        $result = array();
163
164
        if ($query->empty) {
0 ignored issues
show
Bug introduced by
Accessing empty on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
165
            return $result;
166
        }
167
168
        // Get SQL
169
        $sql = $this->prepareSQL($class_name, $query);
170
171
        // Выполним запрос к БД
172
        $db_data = $this->fetch($sql);
0 ignored issues
show
Bug introduced by
It seems like $sql defined by $this->prepareSQL($class_name, $query) on line 169 can also be of type boolean; however, samsonframework\orm\Database::fetch() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
173
174
        //trace($query->virtual_fields);
175
176
        // Выполним запрос к БД и создадим объекты
177
        if ((is_array($db_data)) && (sizeof($db_data) > 0)) {
178
            $result = $this->toRecords($class_name, $db_data, $query->join,
0 ignored issues
show
Bug introduced by
Accessing join on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
179
                array_merge($query->own_virtual_fields, $query->virtual_fields));
0 ignored issues
show
Bug introduced by
Accessing own_virtual_fields on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing virtual_fields on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
180
        }
181
182
        // Вернем коллекцию полученных объектов
183
        return $result;
184
    }
185
186
187
    /**
188
     * @see idb::find_by_id()
189
     */
190
    public function &find_by_id($class_name, $id)
0 ignored issues
show
Coding Style introduced by
Method name "dbMySQL::find_by_id" is not in camel caps format
Loading history...
191
    {
192
        // Получим переменные для запроса
193
        extract($this->__get_table_data($class_name));
0 ignored issues
show
Bug introduced by
$this->__get_table_data($class_name) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
194
195
        // Выполним запрос к БД
196
        $record_data = $this->fetch('SELECT ' . $_sql_select['this'] . ' FROM ' . $_sql_from['this'] . ' WHERE ' . $_table_name . '.' . $_primary . ' = "' . $id . '"');
197
198
        // Если запрос выполнился успешно и получена минимум 1-на запись из БД - создадим объект-запись из неё
199
        $db_records = $this->toRecords($class_name, $record_data);
200
201
        // Переменная для возврата
202
        $ret = null;
203
204
        // Если мы получили 1ю запись то вернем её
205
        if (sizeof($db_records) >= 1) {
206
            $ret = array_shift($db_records);
207
        }
208
209
        // Вернем переменную
210
        return $ret;
211
    }
212
213
    /**
214
     * Выполнить защиту значения поля для его безопасного использования в запросах
215
     *
216
     * @param string $value Значения поля для запроса
217
     * @return string $value Безопасное представление значения поля для запроса
218
     */
219
    protected function protectQueryValue($value)
220
    {
221
        // If magic quotes are on - remove slashes
222
        if (get_magic_quotes_gpc()) {
223
            $value = stripslashes($value);
224
        }
225
226
        // Normally escape string
227
        $value = $this->driver->quote($value);
228
229
        // Return value in quotes
230
        return $value;
231
    }
232
233
    /** @deprecated Use execute() */
234
    public function simple_query($sql)
0 ignored issues
show
Coding Style introduced by
Method name "dbMySQL::simple_query" is not in camel caps format
Loading history...
235
    {
236
        return $this->query($sql);
0 ignored issues
show
Deprecated Code introduced by
The method samsonframework\orm\Database::query() has been deprecated with message: Use execute()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
237
    }
238
239
    /**
240
     * Prepare create & update SQL statements fields
241
     * @param string $className Entity name
242
     * @param Record $object Database object to get values(if needed)
243
     * @param bool $straight Way of forming SQL field statements
244
     * @return array Collection of key => value with SQL fields statements
245
     */
246
    protected function &getQueryFields($className, & $object = null, $straight = false)
247
    {
248
        // Результирующая коллекция
249
        $collection = array();
250
251
        // Установим флаг получения значений атрибутов из переданного объекта
252
        $use_values = isset($object);
0 ignored issues
show
Unused Code introduced by
$use_values 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...
253
254
        // Переберем "настоящее" имена атрибутов схемы данных для объекта
255
        foreach ($className::$_table_attributes as $attribute => $map_attribute) {
256
            // Отметки времени не заполняем
257
            if ($className::$_types[$attribute] == 'timestamp') {
258
                continue;
259
            }
260
261
            // Основной ключ не заполняем
262
            if ($className::$_primary == $attribute) {
263
                continue;
264
            }
265
266
            // Only add attributes that have value
267
            $value = $object->$map_attribute !== null ?
268
                (is_numeric($object->$map_attribute)? $object->$map_attribute : $this->driver->quote($object->$map_attribute))
269
                : 'NULL';
270
271
            // Добавим значение поля, в зависимости от вида вывывода метода
272
            $collection[$map_attribute] = ($straight ? $className::$_table_name . '.' . $map_attribute . '=' : '') . $value;
273
        }
274
275
        // Вернем полученную коллекцию
276
        return $collection;
277
    }
278
279
    /**
280
     * Generic database migration handler
281
     * @param string $classname Class for searching migration methods
282
     * @param string $version_handler External handler for interacting with database version
283
     */
284
    public function migration($classname, $version_handler)
285
    {
286
        if (!is_callable($version_handler)) {
287
            return e('No version handler is passed', E_SAMSON_ACTIVERECORD_ERROR);
0 ignored issues
show
Deprecated Code introduced by
The function e() has been deprecated with message: Use custom exceptions

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
288
        }
289
290
        // Get current database version
291
        $version = call_user_func($version_handler);
292
293
        // DB version migrating mechanism
294
        foreach (get_class_methods($classname) as $m) {
295
            // Parse migration method name to get migrating versions
296
            if (preg_match('/^migrate_(?<from>\d+)_to_(?<to>\d+)/i', $m, $matches)) {
297
                $from = $matches['from'];
298
                $to = $matches['to'];
299
300
                // If we found migration method from current db version
301
                if ($from == $version) {
302
                    // Run migration method
303
                    if (call_user_func(array($version_handler[0], $m)) !== false) {
304
                        // Save current version for further migrating
305
                        $version = $to;
306
307
                        // Call database version changing handler
308
                        call_user_func($version_handler, $to);
309
310
                        // Reload page
311
                        elapsed('Database migration from version: ' . $from . ' -> ' . $to);
312
                    } // Break and error
313
                    else {
314
                        e('Database migration from ## -> ## - has Failed', E_SAMSON_ACTIVERECORD_ERROR,
0 ignored issues
show
Deprecated Code introduced by
The function e() has been deprecated with message: Use custom exceptions

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
315
                            array($from, $to));
316
                        break;
317
                    }
318
                }
319
            }
320
        }
321
    }
322
323
    /** @see idb::profiler() */
324
    public function profiler()
325
    {
326
        // Выведем список объектов из БД
327
        $list = array();
328
329
        // Общее кво созданных объектов
330
        $total_obj_count = 0;
331
332
        // Переберм коллекции созданных объектов
333
        foreach (dbRecord::$instances as $n => $v) {
334
            // Если для данного класса были созданы объекты
335
            if ($c = sizeof($v)) {
336
                // Увеличим общий счетчик созданных объектов
337
                $total_obj_count += $c;
338
339
                // Выведем имя класса и кво созданных объектов
340
                $list[] = '' . $n . '(' . $c . ')';
341
            }
342
        }
343
344
        // Сформируем строку профайлинга
345
        return 'DB: ' . round($this->elapsed,
346
            3) . 'с, ' . $this->query_count . ' запр., ' . $total_obj_count . ' об.(' . implode($list, ',') . ')';
347
    }
348
349
    /** Count query result */
350
    public function innerCount($className, $query)
351
    {
352
        $params = $this->__get_table_data($className);
353
354
        // Get SQL
355
        $sql = 'SELECT Count(*) as __Count FROM (' .
356
            $this->prepareInnerSQL($className, $query, $params) .
357
            ') as __table';
358
359
        $result = $this->fetch($sql);
360
361
        return $result[0]['__Count'];
362
    }
363
364
    //
365
    // Приватный контекст
366
    //
367
368
    /**
369
     * Create SQL request
370
     *
371
     * @param string $class_name Classname for request creating
372
     * @param QueryInterface $query Query with parameters
373
     * @return string SQL string
374
     */
375
    protected function prepareSQL($class_name, QueryInterface $query)
376
    {
377
        //elapsed( 'dbMySQL::find() Начало');
378
        $params = $this->__get_table_data($class_name);
0 ignored issues
show
Documentation introduced by
$class_name is of type string, but the function expects a object<samson\activerecord\unknown_type>.

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
        // Получим переменные для запроса
380
        extract($params);
381
382
        // Текст выборки полей
383
        $select = '`' . $_table_name . '`.*';//$_sql_select['this'];
384
385
        // If virtual fields defined
386 View Code Duplication
        if (sizeof($query->virtual_fields)) {
0 ignored issues
show
Bug introduced by
Accessing virtual_fields on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
387
            $select .= ', ' . "\n" . implode("\n" . ', ', $query->virtual_fields);
0 ignored issues
show
Bug introduced by
Accessing virtual_fields on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
388
        }
389
390
        $from = ' ( ' . $this->prepareInnerSQL($class_name, $query, $params);
391
392
        // Добавим алиас
393
        $from .= ' ) as `' . $_table_name . '`';
394
395
        //trace($query->join);
396
397
        // Iterate related tables
398
        foreach ($query->join as $relation_data) {
0 ignored issues
show
Bug introduced by
Accessing join on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
399
            $c_table = self::$prefix . $relation_data->table;
400
401
            // Если существует требуемая связь
402
            if (isset($_sql_from[$c_table])) {
403
                // Получим текст для выборки данных из связанных таблиц
404
                $select .= ',' . $_sql_select[$c_table];
405
406
                // Получим текст для привязывания таблицы к запросу
407
                $from .= "\n" . ' ' . $_sql_from[$c_table];
408
            } else {
409
                return e('Ошибка! В таблице связей для класса(##), не указана связь с классом(##)',
0 ignored issues
show
Bug Best Practice introduced by
The return type of return e('Ошибка! ...class_name, $c_table)); (boolean) is incompatible with the return type of the parent method samsonframework\orm\Database::prepareSQL of type string|null.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
Deprecated Code introduced by
The function e() has been deprecated with message: Use custom exceptions

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
410
                    E_SAMSON_FATAL_ERROR, array($class_name, $c_table));
411
            }
412
        }
413
414
        // Сформируем строку запроса на поиск записи
415
        $sql = "\n" . 'SELECT ' . $select . "\n" . ' FROM ' . $from;
416
417
        // Получим все условия запроса
418
        $sql .= "\n" . ' WHERE (' . $this->getConditions($query->condition, $class_name) . ')';
0 ignored issues
show
Bug introduced by
Accessing condition on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
419
420
        // Добавим нужные сортировщики
421
        if (sizeof($query->group)) {
0 ignored issues
show
Bug introduced by
Accessing group on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
422
            $sql .= "\n" . ' GROUP BY ' . $query->group[0];
0 ignored issues
show
Bug introduced by
Accessing group on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
423
        }
424
        // Если указана сортировка результатов
425
        if (sizeof($query->order)) {
0 ignored issues
show
Bug introduced by
Accessing order on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
426
            $sql .= "\n" . ' ORDER BY ';
427
            for ($i = 0; $i < sizeof($query->order); $i++) {
0 ignored issues
show
Bug introduced by
Accessing order on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
428
                $item = &$query->order[$i];
0 ignored issues
show
Bug introduced by
Accessing order on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
429
                if (sizeof($item)) {
430
                    $sql .= $item[0] . ' ' . $item[1];
431
                }
432
                if ($i < (sizeof($query->order) - 1)) {
0 ignored issues
show
Bug introduced by
Accessing order on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
433
                    $sql .= ', ';
434
                }
435
            }
436
        }
437
        // Если нужно ограничить к-во записей в выдаче по главной таблице
438 View Code Duplication
        if (sizeof($query->limit)) {
0 ignored issues
show
Bug introduced by
Accessing limit on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
439
            $sql .= "\n" . ' LIMIT ' . $query->limit[0] . (isset($query->limit[1]) ? ',' . $query->limit[1] : '');
0 ignored issues
show
Bug introduced by
Accessing limit on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
440
        }
441
442
        if (isset($GLOBALS['show_sql'])) {
443
            elapsed($sql);
444
        }
445
446
        return $sql;
447
    }
448
449
    protected function prepareInnerSQL($class_name, QueryInterface $query, $params)
450
    {
451
        //trace($class_name);
452
        //print_r($query->own_condition);
453
        // Получим текст цели запроса
454
        $from = 'SELECT ' . $params['_sql_select']['this'];
455
456
        // Если заданны виртуальные поля, добавим для них колонки
457 View Code Duplication
        if (sizeof($query->own_virtual_fields)) {
0 ignored issues
show
Bug introduced by
Accessing own_virtual_fields on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
458
            $from .= ', ' . "\n" . implode("\n" . ', ', $query->own_virtual_fields);
0 ignored issues
show
Bug introduced by
Accessing own_virtual_fields on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
459
        }
460
461
        // From part
462
        $from .= "\n" . ' FROM ' . $params['_sql_from']['this'];
463
464
        // Если существуют условия для главной таблицы в запросе - получим их
465
        if ($query->own_condition->size()) {
0 ignored issues
show
Bug introduced by
Accessing own_condition on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
466
            $from .= "\n" . ' WHERE (' . $this->getConditions($query->own_condition, $class_name) . ')';
0 ignored issues
show
Bug introduced by
Accessing own_condition on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
467
        }
468
469
        // Добавим нужные групировщики
470
        $query->own_group = array_merge($params['_own_group'],
0 ignored issues
show
Bug introduced by
Accessing own_group on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
471
            is_array($query->own_group) ? $query->own_group : array());
0 ignored issues
show
Bug introduced by
Accessing own_group on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
472 View Code Duplication
        if (sizeof($query->own_group)) {
0 ignored issues
show
Bug introduced by
Accessing own_group on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
473
            $from .= "\n" . 'GROUP BY ' . implode(',', $query->own_group);
0 ignored issues
show
Bug introduced by
Accessing own_group on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
474
        }
475
        // Если указана сортировка результатов
476 View Code Duplication
        if (sizeof($query->own_order)) {
0 ignored issues
show
Bug introduced by
Accessing own_order on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
477
            $from .= "\n" . ' ORDER BY ' . $query->own_order[0] . ' ' . $query->own_order[1];
0 ignored issues
show
Bug introduced by
Accessing own_order on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
478
        }
479
        // Если нужно ограничить к-во записей в выдаче по главной таблице
480 View Code Duplication
        if (sizeof($query->own_limit)) {
0 ignored issues
show
Bug introduced by
Accessing own_limit on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
481
            $from .= "\n" . ' LIMIT ' . $query->own_limit[0] . (isset($query->own_limit[1]) ? ',' . $query->own_limit[1] : '');
0 ignored issues
show
Bug introduced by
Accessing own_limit on the interface samsonframework\orm\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
482
        }
483
484
        return $from;
485
    }
486
487
    protected function getConditions(ConditionInterface $cond_group, $class_name)
488
    {
489
        // Соберем сюда все сформированные условия для удобной "упаковки" их в строку
490
        $sql_condition = array();
491
492
        // Переберем все аргументы условий в условной группе условия
493
        foreach ($cond_group as $argument) {
494
            // Если аргумент я вляется группой аргументов, разпарсим его дополнительно
495
            if (is_a($argument, '\samsonframework\orm\ConditionInterface')) {
496
                $sql_condition[] = $this->getConditions($argument, $class_name);
497
            } else {
498
                // Если условие успешно разпознано - добавим его в коллекцию условий
499
                $sql_condition[] = $this->parseCondition($class_name, $argument);
500
            }
501
        }
502
503
        // Соберем все условия условной группы в строку
504
        if (sizeof($sql_condition)) {
505
            return '(' . implode(') ' . $cond_group->relation . ' (', $sql_condition) . ')';
0 ignored issues
show
Bug introduced by
Accessing relation on the interface samsonframework\orm\ConditionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
506
        } // Вернем то что получилось
507
        else {
508
            return '(1=1)';
509
        }
510
    }
511
512
    /**
513
     * "Правильно" разпознать переданный аргумент условия запроса к БД
514
     *
515
     * @param string $class_name Схема сущности БД для которой данные условия
516
     * @param Argument $arg Аругемнт условия для преобразования
517
     * @return string Возвращает разпознанную строку с условием для MySQL
518
     */
519
    protected function parseCondition($class_name, & $arg)
520
    {
521
        // Получим переменные для запроса
522
        extract($this->__get_table_data($class_name));
0 ignored issues
show
Bug introduced by
$this->__get_table_data($class_name) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
Documentation introduced by
$class_name is of type string, but the function expects a object<samson\activerecord\unknown_type>.

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...
523
524
        // Получим "правильное" имя аттрибута сущности и выделим постоянную часть условия
525
        $sql_cond_t = isset($_map[$arg->field]) ? $_map[$arg->field] : $arg->field;
526
527
        // Если аргумент условия - это НЕ массив - оптимизации по более частому условию
528
        if (!is_array($arg->value)) {
529
            // NULL condition
530
            if ($arg->relation === dbRelation::NOTNULL || $arg->relation === dbRelation::ISNULL) {
531
                return $sql_cond_t . $arg->relation;
532
            } // Own condition
533
            else {
534
                if ($arg->relation === dbRelation::OWN) {
535
                    return $arg->field;
536
                } // Regular condition
537
                else {
538
                    return $sql_cond_t . $arg->relation . $this->protectQueryValue($arg->value);
539
                }
540
            }
541
        } // Если аргумент условия - это массив и в нем есть значения
542
        else {
543
            if (sizeof($arg->value)) {
544
                // TODO: Add other numeric types support
545
                // TODO: Get types of joined tables fields
546
547
                // Generate list of values, integer type optimization
548
                $sql_values = isset($class_name::$_types[$arg->field]) && $class_name::$_types[$arg->field] == 'int'
549
                    ? ' IN (' . implode(',', $arg->value) . ')'
550
                    : ' IN ("' . implode('","', $arg->value) . '")';
551
552
                switch ($arg->relation) {
553
                    case dbRelation::EQUAL:
554
                        return $sql_cond_t . $sql_values;
555
                    case dbRelation::NOT_EQUAL:
556
                        return $sql_cond_t . ' NOT ' . $sql_values;
557
                }
558
            }
559
        }
560
    }
561
562
563
    /**
564
     * Create object instance by specified parameters
565
     * @param string $className Object class name
566
     * @param RelationData $metaData Object metadata for creation and filling
0 ignored issues
show
Bug introduced by
There is no parameter named $metaData. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
567
     * @param array $dbData Database record with object data
568
     *
569
     * @return idbRecord Database record object instance
570
     */
571
    public function &createObject(
572
        $className,
573
        $identifier,
574
        array & $attributes,
575
        array & $dbData,
576
        array & $virtualFields = array()
577
    )
0 ignored issues
show
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found newline
Loading history...
578
    {
579
        // If this object instance is not cached
580
        if (!isset(dbRecord::$instances[$className][$identifier]) || isset($dbData['__Count']) || sizeof($virtualFields)) {
581
582
            // Create empry dbRecord ancestor and store it to cache
583
            dbRecord::$instances[$className][$identifier] = new $className($this, new dbQuery());
584
585
            // Pointer to object
586
            $object = &dbRecord::$instances[$className][$identifier];
587
588
            // Set object identifier
589
            $object->id = $identifier;
590
591
            // Fix object connection with DB record
592
            $object->attached = true;
593
594
            // Fill object attributes
595
            foreach ($attributes as $lc_field => $field) {
596
                $object->$lc_field = $dbData[$field];
597
            }
598
599
            // Fill virtual fields
600
            foreach ($virtualFields as $alias => $virtual_field) {
601
                // If DB record contains virtual field data
602
                if (isset($dbData[$alias])) {
603
                    $object->$alias = $dbData[$alias];
604
                }
605
            }
606
607
            return $object;
608
609
        } else { // Get object instance from cache
610
            return dbRecord::$instances[$className][$identifier];
611
        }
612
    }
613
614
    /**
615
     * Преобразовать массив записей из БД во внутреннее представление dbRecord
616
     * @param string $class_name Имя класса
617
     * @param array $response Массив записей полученных из БД
618
     * @return array Коллекцию записей БД во внутреннем формате
619
     * @see dbRecord
620
     */
621
    protected function &toRecords($class_name, array & $response, array $join = array(), array $virtual_fields = array())
622
    {
623
        // Сформируем правильное имя класса
624
        $class_name = ns_classname($class_name, 'samson\activerecord');
0 ignored issues
show
Deprecated Code introduced by
The function ns_classname() has been deprecated with message: use \samson\core\AutoLoader::className() and pass full class name to it without splitting into class name and namespace

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
625
626
        // Результирующая коллекция полученных записей из БД
627
        $collection = array();
628
629
        // Получим переменные для запроса
630
        extract($this->__get_table_data($class_name));
0 ignored issues
show
Bug introduced by
$this->__get_table_data($class_name) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
Documentation introduced by
$class_name is of type string, but the function expects a object<samson\activerecord\unknown_type>.

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...
631
632
        // Generate table metadata for joined tables
633
        $joinedTableData = array();
634
        foreach ($join as $relationData) {
635
636
            // Generate full joined table name(including prefix)
637
            $joinTable = self::$prefix . $relationData->table;
638
639
            // Get real classname of the table without alias
640
            $tableName = $_relation_alias[$joinTable];
641
642
            // Get joined table class metadata
643
            $joinedTableData[$tableName] = $this->__get_table_data($tableName);
644
        }
645
646
        // Получим имя главного
647
        $main_primary = $_primary;
648
649
        // Перебем массив полученных данных от БД - создадим для них объекты
650
        $records_count = sizeof($response);
651
652
        // Идентификатор текущего создаваемого объекта
653
        $main_id = isset($response[0]) ? $response[0][$main_primary] : 0;
654
655
        // Указатель на текущий обрабатываемый объект
656
        $main_obj = null;
657
658
        // Переберем полученные записи из БД
659
        for ($i = 0; $i < $records_count; $i++) {
660
            // Строка данных полученная из БД
661
            $db_row = &$response[$i];
662
663
            // Get object instance
664
            $collection[$main_id] = &$this->createObject($class_name, $main_id, $_attributes, $db_row, $virtual_fields);
665
666
            // Pointer to main object
667
            $main_obj = &$collection[$main_id];
668
669
            // Выполним внутренний перебор строк из БД начиная с текущей строки
670
            // Это позволит нам розабрать объекты полученные со связью один ко многим
671
            // А если это связь 1-1 то цикл выполниться только один раз
672
            for ($j = $i; $j < $records_count; $j++) {
673
                // Строка данных полученная из БД
674
                $db_inner_row = &$response[$j];
675
676
                // Получим идентфиикатор главного объекта в текущей строче БД
677
                $obj_id = $db_inner_row[$main_primary];
678
679
                // Если в строке из БД новый идентификатор
680
                if ($obj_id != $main_id) {
681
                    // Установим новый текущий идентификатор материала
682
                    $main_id = $obj_id;
683
684
                    // Установим индекс главного цикла на строку с новым главным элементом
685
                    // учтем что главный цикл сам увеличит на единицу индекс
686
                    $i = $j - 1;
687
688
                    //trace(' - Найден новый объект на строке №'.$j.'-'.$db_inner_row[$main_primary]);
689
690
                    // Прервем внутренний цикл
691
                    break;
692
                }
693
                //else trace(' + Заполняем данные из строки №'.$j);
694
695
                // Переберем все присоединенные таблицы в запросе
696
                foreach ($join as $relation_data) {
697
                    /**@var \samson\activerecord\RelationData $relation_data */
698
699
                    // If this table is not ignored
700
                    if (!$relation_data->ignore) {
701
702
                        // TODO: Prepare all data in RelationObject to speed up this method
703
704
                        $join_name = $relation_data->relation;
705
706
                        $join_table = self::$prefix . $relation_data->table;
707
708
                        //trace('Filling related table:'.$join_name.'/'.$join_table);
709
710
                        // Get real classname of the table without alias
711
                        $_relation_name = $_relation_alias[$join_table];
712
                        $join_class = str_replace(self::$prefix, '', $relation_data->table);
713
714
                        // Get joined table metadata from previously prepared object
715
                        $r_data = $joinedTableData[$_relation_name];
716
717
                        // Try to get identifier
718
                        if (isset($_relations[$join_table][$r_data['_primary']])) {
719
                            $r_obj_id_field = $_relations[$join_table][$r_data['_primary']];
720
                        } // Получим имя ключевого поля связанного объекта
721
                        else {
722
                            e('Cannot find related table(##) primary field(##) description',
0 ignored issues
show
Deprecated Code introduced by
The function e() has been deprecated with message: Use custom exceptions

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
723
                                E_SAMSON_ACTIVERECORD_ERROR, array($join_table, $r_data['_primary']));
724
                        }
725
726
                        // Если задано имя ключевого поля связанного объекта - создадим его
727
                        if (isset($db_inner_row[$r_obj_id_field])) {
728
                            // Получим ключевое поле связанного объекта
729
                            $r_obj_id = $db_inner_row[$r_obj_id_field];
730
731
                            // Get joined object instance
732
                            $r_obj = &$this->createObject($join_name, $r_obj_id, $_relations[$join_table],
733
                                $db_inner_row);
734
735
                            // Call handler for object filling
736
                            $r_obj->filled();
737
738
                            // TODO: Это старый подход - сохранять не зависимо от алиаса под реальным именем таблицы
739
740
                            // Если связанный объект привязан как один-к-одному - просто довами ссылку на него
741
                            if ($_relation_type[$join_table] == 0) {
742
                                $main_obj->onetoone['_' . $join_table] = $r_obj;
743
                                $main_obj->onetoone['_' . $join_class] = $r_obj;
744
                            } // Иначе создадим массив типа: идентификатор -> объект
745
                            else {
746
                                $main_obj->onetomany['_' . $join_table][$r_obj_id] = $r_obj;
747
                                $main_obj->onetomany['_' . $join_class][$r_obj_id] = $r_obj;
748
                            }
749
                        }
750
                    }
751
                }
752
            }
753
754
            // Call handler for object filling
755
            $main_obj->filled();
756
757
            // Если внутренний цикл дошел до конца остановим главный цикл
758
            if ($j == $records_count) {
759
                break;
760
            }
761
        }
762
763
        // Вернем то что у нас вышло
764
        return $collection;
765
    }
766
}
767