Completed
Push — master ( a7d6b3...227627 )
by Alberto
01:55
created

ActiveRecord::pagination()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 6
rs 9.4285
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 implements \JsonSerializable
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
        }else{
43
            return $model::first($rs->via, $obj->pk());
44
        }
45
    }
46
47 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...
48
        $str = strtolower($name);
49
        $name = static::getTable();
50
        static::$_rs[$str] = (object)[
51
            'model' => $class,
52
            'type'  => self::HAS_MANY,
53
            'via'   => $via ? $via : "{$name}_id"
54
        ];
55
    }
56
57 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...
58
        $str = strtolower($name);
59
        $name = static::getTable();
60
        static::$_rs[$str] = (object)[
61
            'model' => $class,
62
            'type'  => self::HAS_ONE,
63
            'via'   => $via ? $via : "{$name}_id"
64
        ];
65
    }
66
67
    public function jsonSerialize(){
68
       return $this->values;
69
    }
70
71
    public function __get($name){
72
        $val = parent::__get($name);
73
        if($val){
74
            return $val;
75
        }elseif(isset(static::$_rs[$name])){//it's a relationship
76
            $this->populate($name);
77
            return $this->values[$name];
78
        }else{
79
            return null;
80
        }
81
    }
82
83
    static protected function getRelationship($rel){
84
        if(!isset(static::$_rs[$rel]))
85
            throw new \RuntimeException("Invalid relationship '$rel'", 500);
86
        return static::$_rs[$rel];
87
    }
88
89
    public function populate($rel){
90
        $rs = static::getRelationship($rel);
91
        $this->$rel =  static::resolver($rs, $this);
92
    }
93
94
    /**
95
     * Pagination of Results
96
     * @param  Array  $params   [description]
97
     * @param  Array  $values   [description]
98
     * @param  integer $page     [description]
99
     * @param  integer $per_page [description]
100
     * @return Paginator            [description]
101
     */
102
    static  public function pagination($params = [], $values = [], $page = 1, $per_page = 10){
103
        $model =  get_called_class();
104
        unset($params['limit'], $params['offset']);
105
        $sql = QueryGenerator::select($model::getSource(), $model::getDriver(), $params);
106
        return new Paginator($model, $sql, $page, $per_page, $values);
107
    }
108
109
110
    /**
111
     * Actualizar registros.
112
     *
113
     * @param array  $fields
114
     * @param string $where  condiciones
115
     * @param array  $values valores para condiciones
116
     *
117
     * @return int numero de registros actualizados
118
     */
119 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...
120
    {
121
        if ($values !== null && !is_array($values)) {
122
            $values = \array_slice(\func_get_args(), 2);
123
        }
124
        $sql = QueryGenerator::updateAll(\get_called_class(), $fields, $values, $where);
125
        $sth = self::prepare($sql);
126
        $sth->execute($values);
127
128
        return $sth->rowCount();
129
    }
130
131
    /**
132
     * Eliminar registro.
133
     *
134
     * @param string        $where  condiciones
135
     * @param array |string $values valores
136
     *
137
     * @return int numero de registros eliminados
138
     */
139
    public static function deleteAll($where = null, $values = null)
140
    {
141
        $source = static::getSource();
142
        $sql = QueryGenerator::deleteAll($source, $where);
143
        $sth = self::query($sql, $values);
144
145
        return $sth->rowCount();
146
    }
147
148
    /**
149
     * Elimina caracteres que podrian ayudar a ejecutar
150
     * un ataque de Inyeccion SQL.
151
     *
152
     * @param string $sqlItem
153
     *
154
     * @return string
155
     * @throw KumbiaException
156
     */
157
    public static function sqlItemSanitize($sqlItem)
158
    {
159
        $sqlItem = \trim($sqlItem);
160
        if ($sqlItem !== '' && $sqlItem !== null) {
161
            $sql_temp = \preg_replace('/\s+/', '', $sqlItem);
162
            if (!\preg_match('/^[a-zA-Z0-9_\.]+$/', $sql_temp)) {
163
                throw new \RuntimeException('Se esta tratando de ejecutar una operacion maliciosa!');
164
            }
165
        }
166
167
        return $sqlItem;
168
    }
169
170
    /**
171
     * Obtener la primera coincidencia por el campo indicado.
172
     *
173
     * @param string $field  campo
174
     * @param string $value  valor
175
     * @param array  $params parametros adicionales
176
     *                       order: criterio de ordenamiento
177
     *                       fields: lista de campos
178
     *                       join: joins de tablas
179
     *                       group: agrupar campos
180
     *                       having: condiciones de grupo
181
     *                       offset: valor offset
182
     *
183
     * @return ActiveRecord
184
     */
185 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...
186
    {
187
        $field = self::sqlItemSanitize($field);
188
        $params['where'] = "$field = ?";
189
190
        return self::first($params, $value);
191
    }
192
193
    /**
194
     * Obtener la primera coincidencia de las condiciones indicadas.
195
     *
196
     * @param array  $params parametros de bus
197
     * @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...
198
     * @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...
199
     * @param array  $params parametros adicionales
200
     *                       order: criterio de ordenamiento
201
     *                       fields: lista de campos
202
     *                       group: agrupar campos
203
     *                       join: joins de tablas
204
     *                       having: condiciones de grupo
205
     *                       offset: valor offset queda
206
     * @param array  $values valores de busqueda
207
     *
208
     * @return ActiveRecord
209
     */
210
    public static function first($params = [], $values = [])
211
    {
212
        $args = func_get_args();
213
        /*Reescribe el limit*/
214
        $args[0]['limit'] = 1;
215
        $res = self::doQuery($args);
216
217
        return $res->fetch();
218
    }
219
220
    /**
221
     * Obtener todos los registros.
222
     *
223
     * @param array $params
224
     *                      where: condiciones where
225
     *                      order: criterio de ordenamiento
226
     *                      fields: lista de campos
227
     *                      join: joins de tablas
228
     *                      group: agrupar campos
229
     *                      having: condiciones de grupo
230
     *                      limit: valor limit
231
     *                      offset: valor offset
232
     * @param array $values valores de busqueda
233
     *
234
     * @return \PDOStatement
235
     */
236
    public static function all($params = [], $values = [])
237
    {
238
        $res = self::doQuery(func_get_args());
239
240
        return $res->fetchAll();
241
    }
242
243
    /**
244
     * Do a query.
245
     *
246
     * @param array $array params of query
247
     *
248
     * @return \PDOStatement|false
249
     */
250
    protected static function doQuery(array $array)
251
    {
252
        $params = self::getParam($array);
253
        $values = self::getValues($array);
254
        $sql = QueryGenerator::select(static::getSource(), static::getDriver(), $params);
255
        $sth = static::query($sql, $values);
256
257
        return $sth;
258
    }
259
260
    /**
261
     * Retorna los parametros para el doQuery.
262
     *
263
     * @param array $array
264
     *
265
     * @return array
266
     */
267
    protected static function getParam(array &$array)
268
    {
269
        $val = array_shift($array);
270
271
        return is_null($val) ?  [] : $val;
272
    }
273
274
    /**
275
     * Retorna los values para el doQuery.
276
     *
277
     * @param array $array
278
     *
279
     * @return array
280
     */
281
    protected static function getValues(array $array)
282
    {
283
        return isset($array[0]) ?
284
            is_array($array[0]) ? $array[0] : [$array[0]]: $array;
285
    }
286
287
    /**
288
     * Obtener todas las coincidencias por el campo indicado.
289
     *
290
     * @param string $field  campo
291
     * @param string $value  valor
292
     * @param array  $params
293
     *                       order: criterio de ordenamiento
294
     *                       fields: lista de campos
295
     *                       join: joins de tablas
296
     *                       group: agrupar campos
297
     *                       having: condiciones de grupo
298
     *                       limit: valor limit
299
     *                       offset: valor offset
300
     *
301
     * @return \PDOStatement
302
     */
303 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...
304
    {
305
        $field = self::sqlItemSanitize($field);
306
        $params['where'] = "$field = ?";
307
308
        return self::all($params, $value);
309
    }
310
311
    /**
312
     * Cuenta los registros que coincidan con las condiciones indicadas.
313
     *
314
     * @param string $where  condiciones
315
     * @param array  $values valores
316
     *
317
     * @return int
318
     */
319 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...
320
    {
321
        $source = static::getSource();
322
        $sql = QueryGenerator::count($source, $where);
323
        if ($values !== null && !is_array($values)) {
324
            $values = \array_slice(\func_get_args(), 1);
325
        }
326
        $sth = static::query($sql, $values);
327
328
        return $sth->fetch()->count;
329
    }
330
331
    /**
332
     * Paginar.
333
     *
334
     * @param array $params
335
     * @param int   $page    numero de pagina
336
     * @param int   $perPage cantidad de items por pagina
337
     * @param array $values  valores
338
     *
339
     * @return Paginator
340
     */
341
    public static function paginate(array $params, $page, $perPage, $values = null)
342
    {
343
        unset($params['limit'], $params['offset']);
344
        $sql = QueryGenerator::select(static::getSource(), static::getDriver(), $params);
345
346
        // Valores para consulta
347
        if ($values !== null && !\is_array($values)) {
348
            $values = \array_slice(func_get_args(), 3);
349
        }
350
351
        return new Paginator(\get_called_class(), $sql, (int) $page, (int) $perPage, $values);
352
    }
353
354
    /**
355
     * Obtiene todos los registros de la consulta sql.
356
     *
357
     * @param string         $sql
358
     * @param string | array $values
359
     *
360
     * @return array
361
     */
362 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...
363
    {
364
        if (!is_array($values)) {
365
            $values = \array_slice(\func_get_args(), 1);
366
        }
367
368
        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...
369
    }
370
371
    /**
372
     * Obtiene el primer registro de la consulta sql.
373
     *
374
     * @param string         $sql
375
     * @param string | array $values
376
     *
377
     * @return array
378
     */
379 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...
380
    {
381
        if (!is_array($values)) {
382
            $values = \array_slice(\func_get_args(), 1);
383
        }
384
385
        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...
386
    }
387
}
388