Completed
Push — master ( 9fa01f...c95cc6 )
by Dmytro
03:42
created

DBObject::_max()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 7
c 1
b 0
f 1
nc 2
nop 3
dl 11
loc 11
rs 9.4285
1
<?php
2
3
namespace Asymptix\db;
4
5
use Asymptix\core\Tools;
6
7
/**
8
 * DBObject class. Object oriented representation of DB record.
9
 *
10
 * @category Asymptix PHP Framework
11
 * @author Dmytro Zarezenko <[email protected]>
12
 * @copyright (c) 2009 - 2016, Dmytro Zarezenko
13
 *
14
 * @git https://github.com/Asymptix/Framework
15
 * @license http://opensource.org/licenses/MIT
16
 */
17
abstract class DBObject extends \Asymptix\core\Object {
18
19
    /**
20
     * Status constants.
21
     */
22
    const STATUS_ACTIVATED = 1;
23
    const STATUS_DEACTIVATED = 0;
24
25
    const STATUS_REMOVED = 1;
26
    const STATUS_RESTORED = 0;
27
28
    /**
29
     * DB Query object for Prepared Statement.
30
     *
31
     * @var DBPreparedQuery
32
     */
33
    private $dbQuery = null;
34
35
    /**
36
     * Creates new default object.
37
     */
38
    public function __construct() {}
39
40
    /**
41
     * Returns primary key value.
42
     *
43
     * @return mixed.
0 ignored issues
show
Documentation introduced by
The doc-type mixed. could not be parsed: Unknown type name "mixed." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
44
     */
45
    public function getId() {
46
        if (is_null(static::ID_FIELD_NAME)) {
47
            return null;
48
        }
49
50
        return $this->getFieldValue(static::ID_FIELD_NAME);
51
    }
52
53
    /**
54
     * Sets primary key value.
55
     *
56
     * @param mixed $recordId Key vaue.
57
     *
58
     * @return bool Success flag.
59
     * @throws DBCoreException If object has no field with such name.
60
     */
61
    public function setId($recordId) {
62
        return $this->setFieldValue(static::ID_FIELD_NAME, $recordId);
63
    }
64
65
    /**
66
     * Returns name of the primary key field.
67
     *
68
     * @return mixed
69
     */
70
    public static function getIdFieldName() {
71
        return static::ID_FIELD_NAME;
72
    }
73
74
    /**
75
     * Returns DBObject table name.
76
     *
77
     * @return string
78
     */
79
    public static function getTableName() {
80
        return static::TABLE_NAME;
81
    }
82
83
    /**
84
     * Saves activation flag to the database.
85
     *
86
     * @return int Returns the number of affected rows on success, and -1 if
87
     *            the last query failed.
88
     */
89 View Code Duplication
    public function saveActivationFlag() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
90
        return DBCore::doUpdateQuery(
91
            "UPDATE " . static::TABLE_NAME . "
92
                SET activation = ?
93
             WHERE " . static::ID_FIELD_NAME . " = ?
94
             LIMIT 1",
95
            "ii",
96
            [$this->activation, $this->id]
0 ignored issues
show
Documentation introduced by
The property activation does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property id does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
97
        );
98
    }
99
100
    /**
101
     * Detects if current record is activated.
102
     *
103
     * @return bool
104
     *
105
     * @throws DBCoreException If record hos no 'activation' field.
106
     */
107
    public function isActivated() {
108
        $activation = $this->getFieldValue('activation');
109
        if (is_null($activation)) {
110
            throw new DBCoreException("This object has no parameter 'activation'");
111
        }
112
113
        return ($activation > 0);
114
    }
115
116
    /**
117
     * Activates record and save changes into the database.
118
     *
119
     * @return int
120
     */
121
    public function activate() {
122
        $this->setFieldValue('activation', self::STATUS_ACTIVATED);
123
124
        return $this->saveActivationFlag();
125
    }
126
127
    /**
128
     * Deactivates record and save changes into the database.
129
     *
130
     * @return int
131
     */
132
    public function deactivate() {
133
        $this->setFieldValue('activation', self::STATUS_DEACTIVATED);
134
135
        return $this->saveActivationFlag();
136
    }
137
138
    /**
139
     * Changes record activation flag and save changes into the database.
140
     */
141
    public function changeActivation() {
142
        if ($this->isActivated()) {
143
            $this->deactivate();
144
        } else {
145
            $this->activate();
146
        }
147
    }
148
149
    /**
150
     * Saves removement flag to the database.
151
     *
152
     * @return int Returns the number of affected rows on success, and -1 if
153
     *            the last query failed.
154
     */
155 View Code Duplication
    public function saveRemovementFlag() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
156
        return DBCore::doUpdateQuery(
157
            "UPDATE " . static::TABLE_NAME . "
158
                SET removed = ?
159
             WHERE " . static::ID_FIELD_NAME . " = ?
160
             LIMIT 1",
161
            "ii",
162
            [$this->removed, $this->id]
0 ignored issues
show
Documentation introduced by
The property removed does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property id does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
163
        );
164
    }
165
166
    /**
167
     * Detects if current record is removed.
168
     *
169
     * @return bool
170
     *
171
     * @throws DBCoreException If record hos no 'removed' field.
172
     */
173
    public function isRemoved() {
174
        $isRemoved = $this->getFieldValue('removed');
175
        if (is_null($isRemoved)) {
176
            throw new DBCoreException("This object has no parameter 'removed'");
177
        }
178
179
        return ($isRemoved == self::STATUS_REMOVED);
180
    }
181
182
    /**
183
     * Enable removed flag of the record and save changes into the database.
184
     *
185
     * @return int
186
     */
187
    public function remove() {
188
        $this->setFieldValue('removed', self::STATUS_REMOVED);
189
190
        return $this->saveRemovementFlag();
191
    }
192
193
    /**
194
     * Disable removed flag of the record and save changes into the database.
195
     *
196
     * @return int
197
     */
198
    public function restore() {
199
        $this->setFieldValue('removed', self::STATUS_RESTORED);
200
201
        return $this->saveRemovementFlag();
202
    }
203
204
    /**
205
     * Changes record removement flag and save changes into the database.
206
     */
207
    public function changeRemovement() {
208
        if ($this->isRemoved()) {
209
            $this->restore();
210
        } else {
211
            $this->remove();
212
        }
213
    }
214
215
    /**
216
     * Detects if current DBObject represents not existed DB record.
217
     *
218
     * @return bool
219
     */
220
    public function isNewRecord() {
221
        if (is_null(static::ID_FIELD_NAME)) {
222
            return true;
223
        }
224
225
        return ($this->id == 0);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
226
    }
227
228
    /**
229
     * Saves DBObject to the database. If this is a new object - INSERT SQL
230
     *           instruction executes, if existed one - UPDATE.
231
     *
232
     * @param bool $debug Debug mode flag.
233
     *
234
     * @return mixed Primary key value.
235
     * @throws DBCoreException If some database error occurred.
236
     */
237
    public function save($debug = false) {
238
        if ($this->isNewRecord()) {
239
            $insertionId = DBCore::insertDBObject($this, false, $debug);
240
            if (Tools::isInteger($insertionId) && $insertionId > 0) {
241
                $this->setId($insertionId);
242
243
                return $insertionId;
244
            }
245
            throw new DBCoreException("Save database object error");
246
        }
247
        DBCore::updateDBObject($this, $debug);
248
249
        return $this->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
250
    }
251
252
    /**
253
     * Inserts DBObject to the database.
254
     *
255
     * @param bool $ignore Ignore unique indexes or not.
256
     * @param bool Debug mode flag.
257
     *
258
     * @return mixed Primary key value.
259
     * @throws DBCoreException If some database error occurred.
260
     */
261
    public function insert($ignore = false, $debug = false) {
262
        return DBCore::insertDBObject($this, $ignore, $debug);
263
    }
264
265
    /**
266
     * Inits SQL query.
267
     *
268
     * @param string $queryType Type of the SQL query from types list from DBQuery.
269
     * @param array $conditions List of conditions for WHERE instruction.
270
     * @param array $fields List of fields for INSERT or UPDATE types of SQL queries.
271
     *
272
     * @return DBObject Itself.
273
     */
274
    public function initQuery($queryType, $conditions = [], $fields = []) {
275
        $this->dbQuery = new DBPreparedQuery();
276
277
        $this->dbQuery->setType($queryType);
278
        $this->dbQuery->conditions = $conditions;
279
        $this->dbQuery->fields = $fields;
280
281
        /*
282
         * Inits LIMIT if called dynamic select() or update() method.
283
         */
284
        if (is_null($this->dbQuery->limit)) {
285
            $backTrace = debug_backtrace();
286
            if (is_array($backTrace) && isset($backTrace[1])) {
287
                $prevCall = $backTrace[1];
288
                if (is_array($prevCall) && isset($prevCall['type'])) {
289
                    if ($prevCall['type'] == '->') { // dynamic method was called
290
                        $this->dbQuery->limit = 1;
291
                    }
292
                }
293
            }
294
            unset($backTrace);
295
        }
296
297
        return $this;
298
    }
299
300
    /**
301
     * Prepare DBObject for the SELECT SQL query.
302
     *
303
     * @param array $conditions List of the conditions fields
304
     *           (fieldName => fieldValue or sqlCondition => params).
305
     *
306
     * @return DBObject Current object.
307
     */
308
    public function select($conditions = []) {
309
        return $this->initQuery(DBQueryType::SELECT, $conditions);
310
    }
311
312
    /**
313
     * Static way to prepare DBObject for the SELECT SQL query.
314
     *
315
     * @param array $conditions List of the conditions fields
316
     *           (fieldName => fieldValue or sqlCondition => params).
317
     *
318
     * @return DBObject Current object.
319
     */
320
    public static function _select($conditions = []) {
321
        $ref = new \ReflectionClass(get_called_class());
322
        $dbObject = $ref->newInstance();
323
324
        return $dbObject->initQuery(DBQueryType::SELECT, $conditions);
325
    }
326
327
    /**
328
     * Select and returns DB record for current DBObject table by record ID.
329
     *
330
     * @param mixed $recordId Record ID.
331
     * @param bool $debug Debug mode flag.
332
     *
333
     * @return DBObject Record object or null.
334
     */
335
    public static function _get($recordId, $debug = false) {
336
        return static::_select([
337
            static::ID_FIELD_NAME => $recordId
338
        ])->limit(1)->go($debug);
339
    }
340
341
    /**
342
     * Returns result of the COUNT() SQL query.
343
     *
344
     * @param array $conditions Conditions list.
345
     * @param type $debug Debug mode flag.
346
     *
347
     * @return int
348
     */
349 View Code Duplication
    public static function _count($conditions = [], $debug = false) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
350
        $dbQuery = (new DBPreparedQuery())->prepare(
351
            "SELECT COUNT(*) as 'val' FROM " . static::TABLE_NAME,
352
            $conditions
353
        );
354
355
        if (!$debug) {
356
            return (int)DBCore::selectSingleValue($dbQuery);
357
        }
358
        $dbQuery->debug();
359
    }
360
361
    /**
362
     * Returns result of the MAX($field) SQL query.
363
     *
364
     * @param string $field Name of the field.
365
     * @param array $conditions Conditions list.
366
     * @param type $debug Debug mode flag.
367
     *
368
     * @return int
369
     */
370 View Code Duplication
    public static function _max($field, $conditions = [], $debug = false) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
371
        $dbQuery = (new DBPreparedQuery())->prepare(
372
            "SELECT MAX(`" . $field . "`) as 'val' FROM " . static::TABLE_NAME,
373
            $conditions
374
        );
375
376
        if (!$debug) {
377
            return DBCore::selectSingleValue($dbQuery);
378
        }
379
        $dbQuery->debug();
380
    }
381
382
    /**
383
     * Returns result of the MIN($field) SQL query.
384
     *
385
     * @param string $field Name of the field.
386
     * @param array $conditions Conditions list.
387
     * @param type $debug Debug mode flag.
388
     *
389
     * @return int
390
     */
391 View Code Duplication
    public static function _min($field, $conditions = [], $debug = false) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
392
        $dbQuery = (new DBPreparedQuery())->prepare(
393
            "SELECT MIN(`" . $field . "`) as 'val' FROM " . static::TABLE_NAME,
394
            $conditions
395
        );
396
397
        if (!$debug) {
398
            return DBCore::selectSingleValue($dbQuery);
399
        }
400
        $dbQuery->debug();
401
    }
402
403
    /**
404
     * Prepare DBObject for the UPDATE SQL query.
405
     *
406
     * @param type $fields List of fields to be updated
407
     *           (fieldName => fieldValue or sqlAssignment => params).
408
     * @param array $conditions List of the conditions fields
409
     *           (fieldName => fieldValue or sqlCondition => params).
410
     *
411
     * @return DBObject Current object.
412
     */
413
    public function update($fields = [], $conditions = []) {
414
        return $this->initQuery(DBQueryType::UPDATE, $conditions, $fields);
415
    }
416
417
    /**
418
     * Static way to prepare DBObject for the UPDATE SQL query.
419
     *
420
     * @param type $fields List of fields to be updated
421
     *           (fieldName => fieldValue or sqlAssignment => params).
422
     * @param array $conditions List of the conditions fields
423
     *           (fieldName => fieldValue or sqlCondition => params).
424
     *
425
     * @return DBObject Current object.
426
     */
427
    public static function _update($fields = [], $conditions = []) {
428
        $ref = new \ReflectionClass(get_called_class());
429
        $dbObject = $ref->newInstance();
430
431
        return $dbObject->initQuery(DBQueryType::UPDATE, $conditions, $fields);
432
    }
433
434
    /**
435
     * Prepare DBObject for the select query (for ORDER expression).
436
     *
437
     * @param array $order List of order conditions (fieldName => order),
438
     *           order may be 'ASC' OR 'DESC'.
439
     *
440
     * @param array $order
441
     * @return DBObject Current object.
442
     */
443
    public function order($order = null) {
444
        $this->dbQuery->order = $order;
0 ignored issues
show
Documentation Bug introduced by
It seems like $order can be null. However, the property $order is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
445
446
        return $this;
447
    }
448
449
    /**
450
     * Prepare DBObject for the select query (for LIMIT expression).
451
     *
452
     * @param int $offset Limit offset value (or count if this is single
453
     *           parameter).
454
     * @param int $count Number of records to select.
455
     *
456
     * @return DBObject Current object.
457
     */
458
    public function limit($offset = 1, $count = null) {
459 View Code Duplication
        if (is_null($count)) {
0 ignored issues
show
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...
460
            $this->dbQuery->limit = $offset;
461
        } else {
462
            $this->dbQuery->limit = [$offset, $count];
463
        }
464
465
        return $this;
466
    }
467
468
    /**
469
     * Selects DB record(s) for current DBObject table according to params.
470
     *
471
     * @param bool $debug Debug mode flag.
472
     *
473
     * @return mixed DBObject, array of DBObject or null.
474
     * @throws DBCoreException If some DB or query syntax errors occurred.
475
     */
476
    public function go($debug = false) {
477
        switch ($this->dbQuery->getType()) {
478
            case (DBQueryType::SELECT):
479
                $this->dbQuery->query = "SELECT * FROM " . static::TABLE_NAME;
480
                break;
481
            case (DBQueryType::UPDATE):
482
                $this->dbQuery->query = "UPDATE " . static::TABLE_NAME . " SET ";
483
                $this->dbQuery->sqlPushValues($this->dbQuery->fields);
484
                break;
485
            case (DBQueryType::DELETE):
486
                $this->dbQuery->query = "DELETE FROM " . static::TABLE_NAME;
487
                break;
488
        }
489
490
        /*
491
         * Conditions
492
         */
493
        if ($this->isNewRecord()) {
494
            if (!empty($this->dbQuery->conditions)) {
495
                $this->dbQuery->query.= " WHERE ";
496
                $this->dbQuery->sqlPushValues($this->dbQuery->conditions, " AND ");
497
            }
498
        } else {
499
            $this->dbQuery->query.= " WHERE ";
500
            $this->dbQuery->sqlPushValues([static::ID_FIELD_NAME => $this->id]);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Asymptix\db\DBObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
501
        }
502
503
        /*
504
         * Order
505
         */
506
        if ($this->isNewRecord()) {
507
            if (!empty($this->dbQuery->order)) {
508
                $this->dbQuery->query.= " ORDER BY";
509
                if (is_array($this->dbQuery->order)) {
510 View Code Duplication
                    foreach ($this->dbQuery->order as $fieldName => $ord) {
0 ignored issues
show
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...
511
                        $this->dbQuery->query.= " " . $fieldName . " " . $ord . ",";
512
                    }
513
                    $this->dbQuery->query = substr($this->dbQuery->query, 0, strlen($this->dbQuery->query) - 1);
514
                } elseif (is_string($this->dbQuery->order)) {
515
                    $this->dbQuery->query.= " " . $this->dbQuery->order;
516
                }
517
            }
518
        }
519
520
        /*
521
         * Limit
522
         */
523
        $count = null;
524
        if ($this->isNewRecord()) {
525
            if (!is_null($this->dbQuery->limit)) {
526
                if (Tools::isInteger($this->dbQuery->limit)) {
527
                    $this->dbQuery->query.= " LIMIT " . $this->dbQuery->limit;
528
                    $count = $this->dbQuery->limit;
529
                } elseif (is_array($this->dbQuery->limit) && count($this->dbQuery->limit) == 2) {
530
                    $offset = $this->dbQuery->limit[0];
531
                    $count = $this->dbQuery->limit[1];
532 View Code Duplication
                    if (Tools::isInteger($offset) && Tools::isInteger($count)) {
0 ignored issues
show
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...
533
                        $this->dbQuery->query.= " LIMIT " . $offset . ", " . $count;
534
                    } else {
535
                        throw new DBCoreException("Invalid LIMIT param in select() method.");
536
                    }
537
                } else {
538
                    throw new DBCoreException("Invalid LIMIT param in select() method.");
539
                }
540
            }
541
        } else {
542
            $this->dbQuery->query.= " LIMIT 1";
543
            $count = 1;
544
        }
545
546
        if ($debug) {
547
            $this->dbQuery->debug();
548
        } else {
549
            if ($this->dbQuery->isSelector()) {
550
                $stmt = $this->dbQuery->go();
551
                if ($stmt !== false) {
552
                    $data = null;
0 ignored issues
show
Unused Code introduced by
$data 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...
553
                    if ($count !== 1) {
554
                        $data = DBCore::selectDBObjectsFromStatement($stmt, $this);
555
                    } else {
556
                        $data = DBCore::selectDBObjectFromStatement($stmt, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Asymptix\db\DBObject>, but the function expects a string.

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...
557
                    }
558
                    $stmt->close();
559
560
                    return $data;
561
                }
562
563
                return null;
564
            }
565
566
            return $this->dbQuery->go();
567
        }
568
569
        return null;
570
    }
571
572
    /**
573
     * Deletes DB record for current DBObject.
574
     *
575
     * @return mixed Number of affected rows (1 if some record was deleted,
576
     *            0 - if no) or FALSE if some error occurred.
577
     */
578
    public function delete() {
579
        return DBCore::deleteDBObject($this);
580
    }
581
582
    /**
583
     * Deletes DB record by ID or condition.
584
     *
585
     * @param mixed $conditions List of the conditions fields
586
     *           (fieldName => fieldValue or sqlCondition => params).
587
     *           or ID value of the record
588
     * @return DBObject Current object.
589
     */
590
    public static function _delete($conditions = []) {
591
        $ref = new \ReflectionClass(get_called_class());
592
        $dbObject = $ref->newInstance();
593
594
        if (!is_array($conditions)) { // Just record ID provided
595
            $recordId = $conditions;
596
            $conditions = [
597
                $dbObject->getIdFieldName() => $recordId
598
            ];
599
            $dbObject->initQuery(DBQueryType::DELETE, $conditions);
600
            $dbObject->dbQuery->limit = 1;
601
602
            return $dbObject;
603
        }
604
605
        return $dbObject->initQuery(DBQueryType::DELETE, $conditions);
606
    }
607
608
    /**
609
     * Returns DB table field name by it's camelcase variant.
610
     *
611
     * @param string $methodNameFragment
612
     *
613
     * @return string
614
     */
615
    protected function getFieldName($methodNameFragment) {
616
        return substr(strtolower(preg_replace("#([A-Z]{1})#", "_$1", $methodNameFragment)), 1);
617
    }
618
619
}
620