Completed
Push — master ( 2285ee...df6ef2 )
by joanhey
01:57
created

ActiveRecord::jsonSerialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * KumbiaPHP web & app Framework.
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://wiki.kumbiaphp.com/Licencia
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category   Kumbia
16
 *
17
 * @copyright  2005 - 2016  Kumbia Team (http://www.kumbiaphp.com)
18
 * @license    http://wiki.kumbiaphp.com/Licencia     New BSD License
19
 */
20
namespace Kumbia\ActiveRecord;
21
22
/**
23
 * Implementación de patrón ActiveRecord con ayudantes de consultas sql.
24
 */
25
class ActiveRecord extends LiteRecord
26
{
27
28
    const BELONG_TO = 1;
29
    const HAS_MANY  = 2;
30
    const HAS_ONE   = 3;
31
32
    /**
33
     * Describe the relationships
34
     * @var array
35
     */
36
    static protected $rs = [];
37
38
    static public function resolver($rs, $obj){
39
        $model = $rs->model;
40
        if($rs->type === self::HAS_MANY){
41
            return $model::allBy($rs->via, $obj->pk());
42
        }
43
        return $model::first($rs->via, $obj->pk());
44
    }
45
46 View Code Duplication
    static public function hasMany($name, $class, $via = NULL){
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...
47
        $str = strtolower($name);
48
        $name = static::getTable();
49
        static::$rs[$str] = (object)[
50
            'model' => $class,
51
            'type'  => self::HAS_MANY,
52
            'via'   => $via ? $via : "{$name}_id"
53
        ];
54
    }
55
56 View Code Duplication
    static public function hasOne($name, $class, $via = NULL){
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...
57
        $str = strtolower($name);
58
        $name = static::getTable();
59
        static::$rs[$str] = (object)[
60
            'model' => $class,
61
            'type'  => self::HAS_ONE,
62
            'via'   => $via ? $via : "{$name}_id"
63
        ];
64
    }
65
66
    public function __get($key){
67
 
68
        if ($this->$key) {
69
            return $this->$key;
70
        }
71
        //it's a relationship
72
        if (isset(static::$rs[$key])) {
73
            $this->populate($key);
74
            return $this->values[$key];
0 ignored issues
show
Documentation introduced by
The property values does not exist on object<Kumbia\ActiveRecord\ActiveRecord>. 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...
75
        }
76
        return null; //TODO: change for error
77
    }
78
79
    static protected function getRelationship($rel){
80
        if(!isset(static::$rs[$rel]))
81
            throw new \RuntimeException("Invalid relationship '$rel'", 500);
82
        return static::$rs[$rel];
83
    }
84
85
    public function populate($rel){
86
        $rs = static::getRelationship($rel);
87
        $this->$rel =  static::resolver($rs, $this);
88
    }
89
90
    /**
91
     * Pagination of Results
92
     * @param  Array  $params   [description]
93
     * @param  Array  $values   [description]
94
     * @param  integer $page     [description]
95
     * @param  integer $per_page [description]
96
     * @return Paginator            [description]
97
     */
98
    static  public function pagination($params = [], $values = [], $page = 1, $per_page = 10){
99
        $model =  get_called_class();
100
        unset($params['limit'], $params['offset']);
101
        $sql = QueryGenerator::select($model::getSource(), $model::getDriver(), $params);
102
        return new Paginator($model, $sql, $page, $per_page, $values);
103
    }
104
105
106
    /**
107
     * Actualizar registros.
108
     *
109
     * @param array  $fields
110
     * @param string $where  condiciones
111
     * @param array  $values valores para condiciones
112
     *
113
     * @return int numero de registros actualizados
114
     */
115 View Code Duplication
    public static function updateAll(array $fields, $where = null, array $values = [])
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...
116
    {
117
        if ($values !== null && !is_array($values)) {
118
            $values = \array_slice(\func_get_args(), 2);
119
        }
120
        $sql = QueryGenerator::updateAll(\get_called_class(), $fields, $values, $where);
121
        $sth = self::prepare($sql);
122
        $sth->execute($values);
123
124
        return $sth->rowCount();
125
    }
126
127
    /**
128
     * Eliminar registro.
129
     *
130
     * @param string        $where  condiciones
131
     * @param array |string $values valores
132
     *
133
     * @return int numero de registros eliminados
134
     */
135
    public static function deleteAll($where = null, $values = null)
136
    {
137
        $source = static::getSource();
138
        $sql = QueryGenerator::deleteAll($source, $where);
139
        $sth = self::query($sql, $values);
140
141
        return $sth->rowCount();
142
    }
143
144
    /**
145
     * Elimina caracteres que podrian ayudar a ejecutar
146
     * un ataque de Inyeccion SQL.
147
     *
148
     * @param string $sqlItem
149
     *
150
     * @return string
151
     * @throw KumbiaException
152
     */
153
    public static function sqlItemSanitize($sqlItem)
154
    {
155
        $sqlItem = \trim($sqlItem);
156
        if ($sqlItem !== '' && $sqlItem !== null) {
157
            $sql_temp = \preg_replace('/\s+/', '', $sqlItem);
158
            if (!\preg_match('/^[a-zA-Z0-9_\.]+$/', $sql_temp)) {
159
                throw new \RuntimeException('Se esta tratando de ejecutar una operacion maliciosa!');
160
            }
161
        }
162
163
        return $sqlItem;
164
    }
165
166
    /**
167
     * Obtener la primera coincidencia por el campo indicado.
168
     *
169
     * @param string $field  campo
170
     * @param string $value  valor
171
     * @param array  $params parametros adicionales
172
     *                       order: criterio de ordenamiento
173
     *                       fields: lista de campos
174
     *                       join: joins de tablas
175
     *                       group: agrupar campos
176
     *                       having: condiciones de grupo
177
     *                       offset: valor offset
178
     *
179
     * @return ActiveRecord
180
     */
181 View Code Duplication
    public static function firstBy($field, $value, $params = [])
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...
182
    {
183
        $field = self::sqlItemSanitize($field);
184
        $params['where'] = "$field = ?";
185
186
        return self::first($params, $value);
187
    }
188
189
    /**
190
     * Obtener la primera coincidencia de las condiciones indicadas.
191
     *
192
     * @param array  $params parametros de bus
193
     * @param string $field  campo
0 ignored issues
show
Bug introduced by
There is no parameter named $field. 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...
194
     * @param string $value  valor
0 ignored issues
show
Documentation introduced by
There is no parameter named $value. Did you maybe mean $values?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

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

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

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

Loading history...
195
     * @param array  $params parametros adicionales
196
     *                       order: criterio de ordenamiento
197
     *                       fields: lista de campos
198
     *                       group: agrupar campos
199
     *                       join: joins de tablas
200
     *                       having: condiciones de grupo
201
     *                       offset: valor offset queda
202
     * @param array  $values valores de busqueda
203
     *
204
     * @return ActiveRecord
205
     */
206
    public static function first($params = [], $values = [])
207
    {
208
        $args = func_get_args();
209
        /*Reescribe el limit*/
210
        $args[0]['limit'] = 1;
211
        $res = self::doQuery($args);
212
213
        return $res->fetch();
214
    }
215
216
    /**
217
     * Obtener todos los registros.
218
     *
219
     * @param array $params
220
     *                      where: condiciones where
221
     *                      order: criterio de ordenamiento
222
     *                      fields: lista de campos
223
     *                      join: joins de tablas
224
     *                      group: agrupar campos
225
     *                      having: condiciones de grupo
226
     *                      limit: valor limit
227
     *                      offset: valor offset
228
     * @param array $values valores de busqueda
229
     *
230
     * @return \PDOStatement
231
     */
232
    public static function all($params = [], $values = [])
233
    {
234
        $res = self::doQuery(func_get_args());
235
236
        return $res->fetchAll();
237
    }
238
239
    /**
240
     * Do a query.
241
     *
242
     * @param array $array params of query
243
     *
244
     * @return \PDOStatement|false
245
     */
246
    protected static function doQuery(array $array)
247
    {
248
        $params = self::getParam($array);
249
        $values = self::getValues($array);
250
        $sql = QueryGenerator::select(static::getSource(), static::getDriver(), $params);
251
        $sth = static::query($sql, $values);
252
253
        return $sth;
254
    }
255
256
    /**
257
     * Retorna los parametros para el doQuery.
258
     *
259
     * @param array $array
260
     *
261
     * @return array
262
     */
263
    protected static function getParam(array &$array)
264
    {
265
        $val = array_shift($array);
266
267
        return is_null($val) ?  [] : $val;
268
    }
269
270
    /**
271
     * Retorna los values para el doQuery.
272
     *
273
     * @param array $array
274
     *
275
     * @return array
276
     */
277
    protected static function getValues(array $array)
278
    {
279
        return isset($array[0]) ?
280
            is_array($array[0]) ? $array[0] : [$array[0]]: $array;
281
    }
282
283
    /**
284
     * Obtener todas las coincidencias por el campo indicado.
285
     *
286
     * @param string $field  campo
287
     * @param string $value  valor
288
     * @param array  $params
289
     *                       order: criterio de ordenamiento
290
     *                       fields: lista de campos
291
     *                       join: joins de tablas
292
     *                       group: agrupar campos
293
     *                       having: condiciones de grupo
294
     *                       limit: valor limit
295
     *                       offset: valor offset
296
     *
297
     * @return \PDOStatement
298
     */
299 View Code Duplication
    public static function allBy($field, $value, $params = [])
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...
300
    {
301
        $field = self::sqlItemSanitize($field);
302
        $params['where'] = "$field = ?";
303
304
        return self::all($params, $value);
305
    }
306
307
    /**
308
     * Cuenta los registros que coincidan con las condiciones indicadas.
309
     *
310
     * @param string $where  condiciones
311
     * @param array  $values valores
312
     *
313
     * @return int
314
     */
315 View Code Duplication
    public static function count($where = null, $values = null)
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...
316
    {
317
        $source = static::getSource();
318
        $sql = QueryGenerator::count($source, $where);
319
        if ($values !== null && !is_array($values)) {
320
            $values = \array_slice(\func_get_args(), 1);
321
        }
322
        $sth = static::query($sql, $values);
323
324
        return $sth->fetch()->count;
325
    }
326
327
    /**
328
     * Paginar.
329
     *
330
     * @param array $params
331
     * @param int   $page    numero de pagina
332
     * @param int   $perPage cantidad de items por pagina
333
     * @param array $values  valores
334
     *
335
     * @return Paginator
336
     */
337
    public static function paginate(array $params, $page, $perPage, $values = null)
338
    {
339
        unset($params['limit'], $params['offset']);
340
        $sql = QueryGenerator::select(static::getSource(), static::getDriver(), $params);
341
342
        // Valores para consulta
343
        if ($values !== null && !\is_array($values)) {
344
            $values = \array_slice(func_get_args(), 3);
345
        }
346
347
        return new Paginator(\get_called_class(), $sql, (int) $page, (int) $perPage, $values);
348
    }
349
350
    /**
351
     * Obtiene todos los registros de la consulta sql.
352
     *
353
     * @param string         $sql
354
     * @param string | array $values
355
     *
356
     * @return array
357
     */
358 View Code Duplication
    public static function allBySql($sql, $values = null)
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...
359
    {
360
        if (!is_array($values)) {
361
            $values = \array_slice(\func_get_args(), 1);
362
        }
363
364
        return parent::all($sql, $values);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (all() instead of allBySql()). Are you sure this is correct? If so, you might want to change this to $this->all().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
365
    }
366
367
    /**
368
     * Obtiene el primer registro de la consulta sql.
369
     *
370
     * @param string         $sql
371
     * @param string | array $values
372
     *
373
     * @return array
374
     */
375 View Code Duplication
    public static function firstBySql($sql, $values = null)
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...
376
    {
377
        if (!is_array($values)) {
378
            $values = \array_slice(\func_get_args(), 1);
379
        }
380
381
        return parent::first($sql, $values);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (first() instead of firstBySql()). Are you sure this is correct? If so, you might want to change this to $this->first().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
382
    }
383
}
384