1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Arrilot\BitrixModels\Models; |
4
|
|
|
|
5
|
|
|
use Arrilot\BitrixModels\Exceptions\ExceptionFromBitrix; |
6
|
|
|
use Arrilot\BitrixModels\Queries\BaseQuery; |
7
|
|
|
use LogicException; |
8
|
|
|
|
9
|
|
|
abstract class BitrixModel extends BaseBitrixModel |
10
|
|
|
{ |
11
|
|
|
/** |
12
|
|
|
* Bitrix entity object. |
13
|
|
|
* |
14
|
|
|
* @var object |
15
|
|
|
*/ |
16
|
|
|
public static $bxObject; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Corresponding object class name. |
20
|
|
|
* |
21
|
|
|
* @var string |
22
|
|
|
*/ |
23
|
|
|
protected static $objectClass = ''; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Fetch method and parameters. |
27
|
|
|
* |
28
|
|
|
* @var array|string |
29
|
|
|
*/ |
30
|
|
|
public static $fetchUsing = [ |
31
|
|
|
'method' => 'Fetch', |
32
|
|
|
'params' => [], |
33
|
|
|
]; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Constructor. |
37
|
|
|
* |
38
|
|
|
* @param $id |
39
|
|
|
* @param $fields |
40
|
|
|
*/ |
41
|
|
|
public function __construct($id = null, $fields = null) |
42
|
|
|
{ |
43
|
|
|
static::instantiateObject(); |
44
|
|
|
|
45
|
|
|
$this->id = $id; |
46
|
|
|
|
47
|
|
|
$this->fill($fields); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Activate model. |
52
|
|
|
* |
53
|
|
|
* @return bool |
54
|
|
|
*/ |
55
|
|
|
public function activate() |
56
|
|
|
{ |
57
|
|
|
$this->fields['ACTIVE'] = 'Y'; |
58
|
|
|
|
59
|
|
|
return $this->save(['ACTIVE']); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Deactivate model. |
64
|
|
|
* |
65
|
|
|
* @return bool |
66
|
|
|
*/ |
67
|
|
|
public function deactivate() |
68
|
|
|
{ |
69
|
|
|
$this->fields['ACTIVE'] = 'N'; |
70
|
|
|
|
71
|
|
|
return $this->save(['ACTIVE']); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Internal part of create to avoid problems with static and inheritance |
76
|
|
|
* |
77
|
|
|
* @param $fields |
78
|
|
|
* |
79
|
|
|
* @throws ExceptionFromBitrix |
80
|
|
|
* |
81
|
|
|
* @return static|bool |
82
|
|
|
*/ |
83
|
|
|
protected static function internalCreate($fields) |
84
|
|
|
{ |
85
|
|
|
$model = new static(null, $fields); |
86
|
|
|
|
87
|
|
|
if ($model->onBeforeSave() === false || $model->onBeforeCreate() === false) { |
88
|
|
|
return false; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
$bxObject = static::instantiateObject(); |
92
|
|
|
$id = static::internalDirectCreate($bxObject, $model->fields); |
93
|
|
|
$model->setId($id); |
94
|
|
|
|
95
|
|
|
$result = $id ? true : false; |
96
|
|
|
|
97
|
|
|
$model->setEventErrorsOnFail($result, $bxObject); |
98
|
|
|
$model->onAfterCreate($result); |
99
|
|
|
$model->onAfterSave($result); |
100
|
|
|
$model->resetEventErrors(); |
101
|
|
|
$model->throwExceptionOnFail($result, $bxObject); |
102
|
|
|
|
103
|
|
|
return $model; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
public static function internalDirectCreate($bxObject, $fields) |
107
|
|
|
{ |
108
|
|
|
return $bxObject->add($fields); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Delete model. |
113
|
|
|
* |
114
|
|
|
* @return bool |
115
|
|
|
* @throws ExceptionFromBitrix |
116
|
|
|
*/ |
117
|
|
|
public function delete() |
118
|
|
|
{ |
119
|
|
|
if ($this->onBeforeDelete() === false) { |
120
|
|
|
return false; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
$result = static::$bxObject->delete($this->id); |
124
|
|
|
|
125
|
|
|
$this->setEventErrorsOnFail($result, static::$bxObject); |
126
|
|
|
$this->onAfterDelete($result); |
127
|
|
|
$this->resetEventErrors(); |
128
|
|
|
$this->throwExceptionOnFail($result, static::$bxObject); |
129
|
|
|
|
130
|
|
|
return $result; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Save model to database. |
135
|
|
|
* |
136
|
|
|
* @param array $selectedFields save only these fields instead of all. |
137
|
|
|
* @return bool |
138
|
|
|
* @throws ExceptionFromBitrix |
139
|
|
|
*/ |
140
|
|
|
public function save($selectedFields = []) |
141
|
|
|
{ |
142
|
|
|
$fieldsSelectedForSave = is_array($selectedFields) ? $selectedFields : func_get_args(); |
143
|
|
|
$this->fieldsSelectedForSave = $fieldsSelectedForSave; |
144
|
|
View Code Duplication |
if ($this->onBeforeSave() === false || $this->onBeforeUpdate() === false) { |
|
|
|
|
145
|
|
|
$this->fieldsSelectedForSave = []; |
146
|
|
|
return false; |
147
|
|
|
} else { |
148
|
|
|
$this->fieldsSelectedForSave = []; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
$fields = $this->normalizeFieldsForSave($fieldsSelectedForSave); |
152
|
|
|
$result = $fields === null |
153
|
|
|
? true |
154
|
|
|
: $this->internalUpdate($fields, $fieldsSelectedForSave); |
155
|
|
|
|
156
|
|
|
$this->setEventErrorsOnFail($result, static::$bxObject); |
157
|
|
|
$this->onAfterUpdate($result); |
158
|
|
|
$this->onAfterSave($result); |
159
|
|
|
$this->resetEventErrors(); |
160
|
|
|
$this->throwExceptionOnFail($result, static::$bxObject); |
161
|
|
|
|
162
|
|
|
return $result; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* @param $fields |
167
|
|
|
* @param $fieldsSelectedForSave |
168
|
|
|
* @return bool |
169
|
|
|
*/ |
170
|
|
|
protected function internalUpdate($fields, $fieldsSelectedForSave) |
171
|
|
|
{ |
172
|
|
|
return !empty($fields) ? static::$bxObject->update($this->id, $fields) : false; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Scope to get only active items. |
177
|
|
|
* |
178
|
|
|
* @param BaseQuery $query |
179
|
|
|
* |
180
|
|
|
* @return BaseQuery |
181
|
|
|
*/ |
182
|
|
|
public function scopeActive($query) |
183
|
|
|
{ |
184
|
|
|
$query->filter['ACTIVE'] = 'Y'; |
185
|
|
|
|
186
|
|
|
return $query; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Determine whether the field should be stopped from passing to "update". |
191
|
|
|
* |
192
|
|
|
* @param string $field |
193
|
|
|
* @param mixed $value |
194
|
|
|
* @param array $selectedFields |
195
|
|
|
* |
196
|
|
|
* @return bool |
197
|
|
|
*/ |
198
|
|
|
protected function fieldShouldNotBeSaved($field, $value, $selectedFields) |
199
|
|
|
{ |
200
|
|
|
$blacklistedFields = [ |
201
|
|
|
'ID', |
202
|
|
|
'IBLOCK_ID', |
203
|
|
|
'GROUPS', |
204
|
|
|
]; |
205
|
|
|
|
206
|
|
|
return (!empty($selectedFields) && !in_array($field, $selectedFields)) |
207
|
|
|
|| in_array($field, $blacklistedFields) |
208
|
|
|
|| ($field[0] === '~') |
209
|
|
|
|| (substr($field, 0, 9) === 'PROPERTY_') |
210
|
|
|
|| (is_array($this->original) && array_key_exists($field, $this->original) && $this->original[$field] === $value); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Instantiate bitrix entity object. |
215
|
|
|
* |
216
|
|
|
* @throws LogicException |
217
|
|
|
* |
218
|
|
|
* @return object |
219
|
|
|
*/ |
220
|
|
|
public static function instantiateObject() |
221
|
|
|
{ |
222
|
|
|
if (static::$bxObject) { |
223
|
|
|
return static::$bxObject; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
if (class_exists(static::$objectClass)) { |
227
|
|
|
return static::$bxObject = new static::$objectClass(); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
throw new LogicException('Object initialization failed'); |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* Destroy bitrix entity object. |
235
|
|
|
* |
236
|
|
|
* @return void |
237
|
|
|
*/ |
238
|
|
|
public static function destroyObject() |
239
|
|
|
{ |
240
|
|
|
static::$bxObject = null; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Set eventErrors field on error. |
245
|
|
|
* |
246
|
|
|
* @param bool $result |
247
|
|
|
* @param object $bxObject |
248
|
|
|
*/ |
249
|
|
|
protected function setEventErrorsOnFail($result, $bxObject) |
250
|
|
|
{ |
251
|
|
|
if (!$result) { |
252
|
|
|
$this->eventErrors = (array) $bxObject->LAST_ERROR; |
253
|
|
|
} |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Throw bitrix exception on fail |
258
|
|
|
* |
259
|
|
|
* @param bool $result |
260
|
|
|
* @param object $bxObject |
261
|
|
|
* @throws ExceptionFromBitrix |
262
|
|
|
*/ |
263
|
|
|
protected function throwExceptionOnFail($result, $bxObject) |
264
|
|
|
{ |
265
|
|
|
if (!$result) { |
266
|
|
|
throw new ExceptionFromBitrix($bxObject->LAST_ERROR); |
267
|
|
|
} |
268
|
|
|
} |
269
|
|
|
} |
270
|
|
|
|
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.