Completed
Push — master ( 03a792...ea49f3 )
by Alberto
02:34
created

ActiveRecord::__call()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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