1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<?php
namespace common\models\psources;
use Yii;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;
use yii\web\Linkable;
use yii\web\Link;
class CommonActiveRecord extends ActiveRecord
{
public $cacheKeyStorage = []; //缓存key寄存器
public function toArray(array $fields = [], array $expand = [], $recursive = true)
{
$data = [];
$cachePrefix = __CLASS__;
$cache = Yii::$app->cache;
foreach ($this->resolveFields($fields, $expand) as $field => $definition) {
if (strpos($field, '.')) {
$fieldChunks = explode('.', $field);
$primaryKey = is_array($this->primaryKey) ? implode('-', $this->primaryKey) : $this->primaryKey;
$uniqueRelationCacheKey = "{$cachePrefix}_{$primaryKey}_{$fieldChunks[0]}";
$this->addCacheKeyToStorage($uniqueRelationCacheKey);
$relation = $cache->get($uniqueRelationCacheKey);
if (!$relation) {
$relation = $this->{$fieldChunks[0]};
$cache->set($uniqueRelationCacheKey, $relation);
}
if (is_array($relation)) {
foreach ($relation as $relatedField => $relatedObject) {
if (!is_object($relatedObject)) {
continue;
}
$data[$fieldChunks[0]][$relatedField][$fieldChunks[1]] = $this->getRelationField($relatedObject, $fieldChunks[1]);
}
} else {
if (!is_object($relation)) {
continue;
}
$data[$fieldChunks[0]][$fieldChunks[1]] = $this->getRelationField($relation, $fieldChunks[1]);
}
} else {
$data[$field] = is_string($definition) ? $this->$definition : call_user_func($definition, $this, $field);
}
}
$this->deleteStorageCaches();
if ($this instanceof Linkable) {
$data['_links'] = Link::serialize($this->getLinks());
}
return $recursive ? ArrayHelper::toArray($data) : $data;
}
/**
* This method also will check relations which are declared in [[extraFields()]]
* to determine which related fields can be returned.
* @inheritdoc
*/
protected function resolveFields(array $fields, array $expand)
{
$result = [];
foreach ($this->fields() as $field => $definition) {
if (is_integer($field)) {
$field = $definition;
}
if (empty($fields) || in_array($field, $fields, true)) {
$result[$field] = $definition;
}
}
if (empty($expand)) {
return $result;
}
$extraFieldsKeys = array_keys($this->extraFields());
foreach($expand as $expandedAttribute) {
if(in_array(explode('.',$expandedAttribute)[0], $this->extraFields())) {
$result[$expandedAttribute] = $expandedAttribute;
}else if(in_array($expandedAttribute, $extraFieldsKeys)) {
$result[$expandedAttribute] = $this->extraFields()[$expandedAttribute];
}
}
return $result;
}
/**
* Additional method to check the related model has specified field
*/
private function getRelationField($relatedRecord, $field)
{
if (!$relatedRecord->hasAttribute($field) && !$relatedRecord->isRelationPopulated($field)) {
throw new \yii\web\ServerErrorHttpException(sprintf(
"Related record '%s' does not have attribute '%s'",
get_class($relatedRecord), $field)
);
}
if($relatedRecord->hasAttribute($field)) {
return ArrayHelper::toArray($relatedRecord)[$field];
} else {
return $relatedRecord->{$field};
}
}
public static function quoteDbName($dbname)
{
return '`' . $dbname . '`';
}
/**
* 添加cache key到寄存器
* @param type $cacheKey
*/
public function addCacheKeyToStorage($cacheKey)
{
if(!in_array($cacheKey, $this->cacheKeyStorage)) {
$this->cacheKeyStorage[] = $cacheKey;
}
}
/**
* 删除寄存器里所有的cache
*/
public function deleteStorageCaches()
{
foreach($this->cacheKeyStorage as $cacheKey) {
Yii::$app->cache->delete($cacheKey);
}
}
}