Completed
Push — master ( 6ae3d1...04c69a )
by Alberto
03:47 queued 01:23
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
    /**
39
     * Store all information about relationship for populate methods
40
     * @var array
41
     */
42
    protected $_populate = [];
43
44
    static function resolver($rs, $obj){
0 ignored issues
show
Best Practice introduced by ashrey
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

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