1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* ActiveRecord for API. |
4
|
|
|
* |
5
|
|
|
* @see https://github.com/hiqdev/yii2-hiart |
6
|
|
|
* @package yii2-hiart |
7
|
|
|
* @license BSD-3-Clause |
8
|
|
|
* @copyright Copyright (c) 2015-2017, HiQDev (http://hiqdev.com/) |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace hiqdev\hiart; |
12
|
|
|
|
13
|
|
|
use Exception; |
14
|
|
|
use yii\caching\Dependency; |
15
|
|
|
use yii\db\Query as BaseQuery; |
16
|
|
|
use yii\db\QueryInterface; |
17
|
|
|
use yii\helpers\ArrayHelper; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Query represents API query in a way that is independent from a concrete API. |
21
|
|
|
* Holds API query information: |
22
|
|
|
* - general query data |
23
|
|
|
* - action: action to be performed with this query, e.g. search, insert, update, delete |
24
|
|
|
* - options: other additional options, like |
25
|
|
|
* - raw: do not decode response |
26
|
|
|
* - batch: batch(bulk) request |
27
|
|
|
* - timeout, ... |
28
|
|
|
* - insert/update query data |
29
|
|
|
* - body: insert or update data |
30
|
|
|
* - select query data |
31
|
|
|
* - select: fields to select |
32
|
|
|
* - count: marks count query |
33
|
|
|
* - from: entity being queried, e.g. user |
34
|
|
|
* - join: data how to join with other entities |
35
|
|
|
* - other standard query options provided with QueryTrait: |
36
|
|
|
* - where, limit, offset, orderBy, indexBy. |
37
|
|
|
*/ |
38
|
|
|
class Query extends BaseQuery implements QueryInterface |
39
|
|
|
{ |
40
|
|
|
/** |
41
|
|
|
* @var string action that this query performs |
42
|
|
|
*/ |
43
|
|
|
public $action; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var array query options e.g. raw, batch |
47
|
|
|
*/ |
48
|
|
|
public $options = []; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var string the COUNT expression |
52
|
|
|
*/ |
53
|
|
|
public $count; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var int the default number of seconds that query results can remain valid in cache. |
57
|
|
|
* Use 0 to indicate that the cached data will never expire. And use a negative number to indicate |
58
|
|
|
* query cache should not be used. |
59
|
|
|
* @see cache() |
60
|
|
|
*/ |
61
|
|
|
public $queryCacheDuration; |
62
|
2 |
|
|
63
|
|
|
/** |
64
|
2 |
|
* @var Dependency the dependency to be associated with the cached query result for this command |
65
|
|
|
* @see cache() |
66
|
|
|
*/ |
67
|
|
|
public $queryCacheDependency; |
68
|
2 |
|
|
69
|
|
|
/** |
70
|
2 |
|
* @param null|Connection $db |
71
|
|
|
* @throws Exception |
72
|
|
|
* @return Command |
73
|
|
|
*/ |
74
|
|
|
public function createCommand($db = null) |
75
|
|
|
{ |
76
|
|
|
if ($db === null) { |
77
|
|
|
throw new Exception('no db given to Query::createCommand'); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
$request = $db->getQueryBuilder()->build($this); |
81
|
|
|
|
82
|
|
|
$command = $db->createCommand($request); |
83
|
|
|
|
84
|
|
|
if ($this->queryCacheDuration !== null) { |
85
|
|
|
$command->cache($this->queryCacheDuration, $this->queryCacheDependency); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
return $command; |
|
|
|
|
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Enables query cache for this command. |
93
|
|
|
* @param int $duration the number of seconds that query result of this command can remain valid in the cache. |
94
|
|
|
* If this is not set, the value of [[Connection::queryCacheDuration]] will be used instead. |
95
|
|
|
* Use 0 to indicate that the cached data will never expire. |
96
|
|
|
* @param Dependency $dependency the cache dependency associated with the cached query result |
97
|
|
|
* @return $this the command object itself |
98
|
|
|
*/ |
99
|
|
|
public function cache($duration = null, $dependency = null) |
100
|
|
|
{ |
101
|
|
|
$this->queryCacheDuration = $duration; |
102
|
|
|
$this->queryCacheDependency = $dependency; |
103
|
|
|
return $this; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public function one($db = null) |
107
|
|
|
{ |
108
|
2 |
|
$this->limit(1); |
109
|
|
|
|
110
|
2 |
|
$row = parent::one($db); |
111
|
|
|
if (ArrayHelper::isIndexed($row)) { |
|
|
|
|
112
|
|
|
return reset($row); |
113
|
2 |
|
} |
114
|
|
|
|
115
|
2 |
|
return $row; |
116
|
|
|
} |
117
|
|
|
|
118
|
2 |
|
public function count($q = '*', $db = null) |
119
|
|
|
{ |
120
|
2 |
|
$this->count = $q; |
121
|
|
|
return $this->createCommand($db)->count(); |
|
|
|
|
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.