Completed
Push — master ( 369f62...c99037 )
by joanhey
01:53
created

ActiveRecord::getRelationship()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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