1 | <?php |
||
32 | class AuditEntry extends ActiveRecord |
||
33 | { |
||
34 | /** |
||
35 | * @var bool |
||
36 | */ |
||
37 | protected $autoSerialize = false; |
||
38 | |||
39 | /** |
||
40 | * @inheritdoc |
||
41 | */ |
||
42 | 195 | public static function tableName() |
|
43 | { |
||
44 | 195 | return '{{%audit_entry}}'; |
|
45 | } |
||
46 | |||
47 | /** |
||
48 | * @param bool $initialise |
||
49 | * @return static |
||
50 | */ |
||
51 | 117 | public static function create($initialise = true) |
|
59 | |||
60 | /** |
||
61 | * Returns all linked AuditError instances |
||
62 | * (Called `linkedErrors()` to avoid confusion with the `getErrors()` method) |
||
63 | * @return ActiveQuery |
||
64 | */ |
||
65 | 9 | public function getLinkedErrors() |
|
66 | { |
||
67 | 9 | return static::hasMany(AuditError::className(), ['entry_id' => 'id']); |
|
68 | } |
||
69 | |||
70 | /** |
||
71 | * Returns all linked AuditTrail instances |
||
72 | * @return ActiveQuery |
||
73 | */ |
||
74 | 9 | public function getTrails() |
|
75 | { |
||
76 | 9 | return static::hasMany(AuditTrail::className(), ['entry_id' => 'id']); |
|
77 | } |
||
78 | |||
79 | /** |
||
80 | * Returns all linked AuditMail instances |
||
81 | * @return ActiveQuery |
||
82 | */ |
||
83 | 9 | public function getMails() |
|
84 | { |
||
85 | 9 | return static::hasMany(AuditMail::className(), ['entry_id' => 'id']); |
|
86 | } |
||
87 | |||
88 | /** |
||
89 | * Returns all linked AuditJavascript instances |
||
90 | * @return ActiveQuery |
||
91 | */ |
||
92 | 9 | public function getJavascripts() |
|
93 | { |
||
94 | 9 | return static::hasMany(AuditJavascript::className(), ['entry_id' => 'id']); |
|
95 | } |
||
96 | |||
97 | /** |
||
98 | * Returns all linked data records |
||
99 | * @return ActiveQuery |
||
100 | */ |
||
101 | 3 | public function getData() |
|
102 | { |
||
103 | 3 | return static::hasMany(AuditData::className(), ['entry_id' => 'id'])->indexBy('type'); |
|
104 | } |
||
105 | |||
106 | /** |
||
107 | * Writes a number of associated data records in one go. |
||
108 | * @param $batchData |
||
109 | * @param bool $compact |
||
110 | * @throws \yii\db\Exception |
||
111 | */ |
||
112 | 45 | public function addBatchData($batchData, $compact = true) |
|
113 | { |
||
114 | 45 | $columns = ['entry_id', 'type', 'created', 'data']; |
|
115 | 45 | $rows = []; |
|
116 | 45 | $params = []; |
|
117 | 45 | $date = date('Y-m-d H:i:s'); |
|
118 | // Some database like postgres depend on the data being escaped correctly. |
||
119 | // PDO can take care of this if you define the field as a LOB (Large OBject), but unfortunately Yii does threat values |
||
120 | // for batch inserts the same way. This code adds a number of literals instead of the actual values |
||
121 | // so that they can be bound right before insert and still get escaped correctly |
||
122 | 45 | foreach ($batchData as $type => $data) { |
|
123 | 45 | $param = ':data_' . str_replace('/', '_', $type); |
|
124 | 45 | $rows[] = [$this->id, $type, $date, new Expression($param)]; |
|
125 | 45 | $params[$param] = [Helper::serialize($data, $compact), \PDO::PARAM_LOB]; |
|
126 | 45 | } |
|
127 | 45 | static::getDb()->createCommand()->batchInsert(AuditData::tableName(), $columns, $rows)->bindValues($params)->execute(); |
|
128 | 45 | } |
|
129 | |||
130 | /** |
||
131 | * @param $type |
||
132 | * @param $data |
||
133 | * @param bool|true $compact |
||
134 | * @throws \yii\db\Exception |
||
135 | */ |
||
136 | 6 | public function addData($type, $data, $compact = true) |
|
137 | { |
||
138 | // Make sure to mark data as a large object so it gets escaped |
||
139 | $record = [ |
||
140 | 6 | 'entry_id' => $this->id, |
|
141 | 6 | 'type' => $type, |
|
142 | 6 | 'created' => date('Y-m-d H:i:s'), |
|
143 | 6 | 'data' => [Helper::serialize($data, $compact), \PDO::PARAM_LOB], |
|
144 | 6 | ]; |
|
145 | 6 | static::getDb()->createCommand()->insert(AuditData::tableName(), $record)->execute(); |
|
146 | 6 | } |
|
147 | |||
148 | /** |
||
149 | * Records the current application state into the instance. |
||
150 | */ |
||
151 | 117 | public function record() |
|
152 | { |
||
153 | 117 | $app = Yii::$app; |
|
154 | 117 | $request = $app->request; |
|
155 | |||
156 | 117 | $this->route = $app->requestedAction ? $app->requestedAction->uniqueId : null; |
|
157 | 117 | if ($request instanceof \yii\web\Request) { |
|
158 | 117 | $this->user_id = Audit::getInstance()->getUserId(); |
|
159 | 117 | $this->ip = $this->getUserIP(); |
|
160 | 117 | $this->ajax = $request->isAjax; |
|
161 | 117 | $this->request_method = $request->method; |
|
162 | 117 | } else if ($request instanceof \yii\console\Request) { |
|
163 | $this->request_method = 'CLI'; |
||
164 | } |
||
165 | |||
166 | 117 | $this->save(false); |
|
167 | 117 | } |
|
168 | |||
169 | /** |
||
170 | * @return bool |
||
171 | */ |
||
172 | 75 | public function finalize() |
|
173 | { |
||
174 | 75 | $app = Yii::$app; |
|
175 | 75 | $request = $app->request; |
|
176 | |||
177 | 75 | if (!$this->user_id && $request instanceof \yii\web\Request) { |
|
178 | 75 | $this->user_id = Audit::getInstance()->getUserId(); |
|
179 | 75 | } |
|
180 | |||
181 | 75 | $this->duration = microtime(true) - YII_BEGIN_TIME; |
|
182 | 75 | $this->memory_max = memory_get_peak_usage(); |
|
183 | 75 | return $this->save(false, ['duration', 'memory_max', 'user_id']); |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * @return array |
||
188 | */ |
||
189 | 15 | public function attributeLabels() |
|
201 | |||
202 | /** |
||
203 | * @return bool |
||
204 | */ |
||
205 | public function hasRelatedData() |
||
206 | { |
||
207 | if ($this->getLinkedErrors()->count()) { |
||
208 | return true; |
||
209 | } |
||
210 | if ($this->getJavascripts()->count()) { |
||
211 | return true; |
||
221 | |||
222 | /** |
||
223 | * @return string |
||
224 | */ |
||
225 | public function getUserIP() |
||
232 | |||
233 | } |
||
234 |
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.