Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
ActiveRecordImplementation.php
1<?php
2
4
10use Bitrix\Im\Model\EO_Chat;
11use Bitrix\Im\Model\EO_Message;
12use Bitrix\Im\Model\EO_MessageParam;
17
21trait ActiveRecordImplementation
22{
24 protected $dataObject;
25
26 // Object changed flag
27 protected bool $isChanged = true;
28
29 // Object marked to drop
30 protected bool $markedDrop = false;
31
36 protected static function mirrorDataEntityFields(): array
37 {
39 return [];
40 }
41
45 public function getDataEntity(): EntityObject
46 {
47 if ($this->dataObject === null)
48 {
53 $dataClass = static::getDataClass();
54 $entityObjectClass = $dataClass::getObjectClass();
55 $this->dataObject = new $entityObjectClass;
56 }
57
58 return $this->dataObject;
59 }
60
65 protected function setDataEntity(EntityObject $dataObject): self
66 {
67 $this->dataObject = $dataObject;
68 return $this;
69 }
70
74 public function load($source): Result
75 {
76 $result = new Result;
77
78 if (is_numeric($source))
79 {
80 $source = (int)$source;
85 $dataClass = static::getDataClass();
86 $dataObject = $dataClass::getByPrimary($source)->fetchObject();
87
88 if (
89 $dataObject instanceof EntityObject
90 && $dataObject->hasId()
91 )
92 {
93 $result = $this->initByDataEntity($dataObject);
94 }
95 else
96 {
97 $result->addError(new Error(Error::NOT_FOUND));
98 }
99 }
100
101 elseif ($source instanceof EntityObject)
102 {
103 $result = $this->initByDataEntity($source);
104 }
105
106 elseif (is_array($source))
107 {
108 $result = $this->initByArray($source);
109 }
110 else
111 {
112 $result->addError(new Error(Error::NOT_FOUND));
113 }
114
115 if ($result->isSuccess() && $this->getPrimaryId())
116 {
117 $this->markChanged(false);
118
119 if (
120 $this instanceof RegistryEntry
121 && $this->getRegistry()
122 )
123 {
124 $this->getRegistry()[$this->getPrimaryId()] = $this;
125 }
126 }
127
128 return $result;
129 }
130
134 protected function initByDefault(): void
135 {
136 foreach (static::mirrorDataEntityFields() as $field)
137 {
138 if (
139 !isset($field['primary'])
140 && !isset($field['alias'])
141 && isset($field['field'], $field['default'])
142 && !isset($this->{$field['field']})
143 && ($default = $field['default'])
144 && is_string($default)
145 && is_callable([$this, $default])
146 )
147 {
148 $this->{$field['field']} = $this->$default();
149 }
150 }
151 }
152
157 protected function initByDataEntity(EntityObject $dataObject): Result
158 {
159 $result = new Result;
160
161 $this->setDataEntity($dataObject);
162
163 foreach (static::mirrorDataEntityFields() as $offset => $field)
164 {
165 if (isset($field['alias']) || !isset($field['field']))
166 {
167 continue;
168 }
169 if ($this->getDataEntity()->has($offset))
170 {
171 if (
172 isset($field['loadFilter'])
173 && ($loadFilter = $field['loadFilter'])
174 && is_string($loadFilter)
175 && is_callable([$this, $loadFilter])
176 )
177 {
178 $this->{$field['field']} = $this->$loadFilter($this->getDataEntity()->get($offset));
179 }
180 else
181 {
182 $this->{$field['field']} = $this->getDataEntity()->get($offset);
183 }
184 }
185 }
186
187 if ($result->isSuccess() && $this->getPrimaryId())
188 {
189 $this->markChanged(false);
190 }
191
192 return $result;
193 }
194
199 protected function initByArray(array $source): Result
200 {
201 $result = new Result;
202 $fieldsToFill = $source;
203
204 if ($this->hasPrimary($source))
205 {
206 [$ormFields, $fieldsToFill] = $this->separateFieldsOrmAndOther($source);
207 $result = $this->initByDataEntity(static::getDataClass()::getObjectClass()::wakeUp($ormFields));
208 if (!$result->isSuccess())
209 {
210 return $result;
211 }
212 }
213
214 if (!empty($fieldsToFill))
215 {
216 $this->fill($fieldsToFill);
217 }
218
219 if ($result->isSuccess() && $this->getPrimaryId())
220 {
221 $this->markChanged(false);
222 }
223
224 return $result;
225 }
226
227 protected function hasPrimary(array $source): bool
228 {
229 $fields = static::mirrorDataEntityFields();
230
231 foreach ($source as $key => $value)
232 {
233 if (!isset($fields[$key]))
234 {
235 continue;
236 }
237
238 $field = isset($fields[$key]['alias']) ? $fields[$fields[$key]['alias']] : $fields[$key];
239
240 if (isset($field['primary']) && $field['primary'])
241 {
242 return true;
243 }
244 }
245
246 return false;
247 }
248
249 protected function separateFieldsOrmAndOther(array $source): array
250 {
251 $fields = static::mirrorDataEntityFields();
253 $entity = static::getDataClass()::getEntity();
254 $ormFields = [];
255 $otherFields = [];
256
257 foreach ($source as $key => $value)
258 {
259 if (!isset($fields[$key]))
260 {
261 continue;
262 }
263
264 $fieldName = $fields[$key]['alias'] ?? $key;
265
266 if ($entity->hasField($fieldName) && !($entity->getField($fieldName) instanceof Relation))
267 {
268 if (
269 $value !== null
270 && $entity->getField($fieldName) instanceof \Bitrix\Main\ORM\Fields\DatetimeField
271 && is_string($value)
272 )
273 {
274 if (is_string($value) && !is_numeric($value))
275 {
276 $value = DateTime::tryParse($value) ?? DateTime::tryParse($value, 'Y-m-d H:i:s') ?? $value;
277 }
278 if (is_numeric($value))
279 {
280 $value = DateTime::createFromTimestamp((int)$value);
281 }
282 }
283 $ormFields[$fieldName] = $value;
284 }
285 else
286 {
287 $otherFields[$key] = $value;
288 }
289 }
290
291 return [$ormFields, $otherFields];
292 }
293
294 public function prepareFields(): Result
295 {
296 $result = new Result;
297
298 foreach (static::mirrorDataEntityFields() as $offset => $field)
299 {
300 if (isset($field['primary']) || isset($field['alias']) || (isset($field['skipSave']) && $field['skipSave'] === true))
301 {
302 continue;
303 }
304
305 if (
306 isset($field['beforeSave'])
307 && ($beforeSave = $field['beforeSave'])
308 && is_string($beforeSave)
309 && is_callable([$this, $beforeSave])
310 )
311 {
313 $check = $this->$beforeSave();
314 if (!$check->isSuccess())
315 {
316 $result->addErrors($check->getErrors());
317 continue;
318 }
319 }
320
321 if (isset($field['field'], $this->{$field['field']}))
322 {
323 if (
324 isset($field['saveFilter'])
325 && ($saveFilter = $field['saveFilter'])
326 && is_string($saveFilter)
327 && is_callable([$this, $saveFilter])
328 )
329 {
330 $this->getDataEntity()->set($offset, $this->$saveFilter($this->{$field['field']}));
331 }
332 else
333 {
334 $this->getDataEntity()->set($offset, $this->{$field['field']});
335 }
336
337 $this->markChanged($this->isChanged || $this->getDataEntity()->isChanged($offset));
338 }
339 }
340
341 return $result;
342 }
343
347 public function save(): Result
348 {
349 $result = $this->prepareFields();
350 if (!$result->isSuccess())
351 {
352 return $result;
353 }
354 if (!$this->isChanged())
355 {
356 return $result;
357 }
358
359 $saveResult = $this->getDataEntity()->save();
360 if ($saveResult->isSuccess())
361 {
362 $this->updateState();
363
364 $this->setPrimaryId((int)$saveResult->getId());
365
366 if (
367 $this instanceof RegistryEntry
368 && $this->getRegistry()
369 )
370 {
371 $this->getRegistry()[$this->getPrimaryId()] = $this;
372 }
373
374 $this->markChanged(false);
375 }
376 else
377 {
378 $result->addErrors($saveResult->getErrors());
379 }
380
381 return $result;
382 }
383
384 protected function updateState(): Result
385 {
386 return $this->initByDataEntity($this->getDataEntity());
387 }
388
392 public function delete(): Result
393 {
394 $this->markDrop();
395 $result = new Result;
396 if ($this->getDataEntity()->hasId())
397 {
398 $deleteResult = $this->getDataEntity()->delete();
399 if (!$deleteResult->isSuccess())
400 {
401 return $result->addErrors($deleteResult->getErrors());
402 }
403 }
404
405 if (
406 $this instanceof RegistryEntry
407 && $this->getRegistry()
408 )
409 {
410 unset($this->getRegistry()[$this->getPrimaryId()]);
411 }
412
413 return $result;
414 }
415
420 public function markChanged(?bool $state = null): self
421 {
422 if ($state === null)
423 {
424 $this->isChanged = true;
425 }
426 else
427 {
428 $this->isChanged = $state;
429 }
430 if ($this->isChanged)
431 {
432 $this->markedDrop = false;
433 }
434 return $this;
435 }
436
441 public function isChanged(): bool
442 {
443 return $this->isChanged;
444 }
445
450 public function markDrop(): self
451 {
452 $this->isChanged = false;
453 $this->markedDrop = true;
454 return $this;
455 }
456
461 public function isDeleted(): bool
462 {
463 return $this->markedDrop;
464 }
465
466 public function fillActual(array $fieldsToFill): self
467 {
468 foreach ($fieldsToFill as $fieldName)
469 {
470 if ($this->getDataEntity()->entity->hasField($fieldName))
471 {
472 $this->getDataEntity()->unset($fieldName);
473 }
474 }
475 $this->getDataEntity()->fill($fieldsToFill);
476
477 $this->updateState();
478
479 return $this;
480 }
481
487 public function fill(array $source): self
488 {
489 $fields = static::mirrorDataEntityFields();
490
491 foreach ($fields as $offset => $field)
492 {
493 if (isset($source[$offset]))
494 {
495 if (isset($field['primary']))
496 {
497 continue;
498 }
499 if (isset($field['alias']))
500 {
501 $field = $fields[$field['alias']];
502 }
503 if (
504 isset($field['set'])
505 && ($setter = $field['set'])
506 && is_string($setter)
507 && is_callable([$this, $setter])
508 )
509 {
510 $this->$setter($source[$offset]);
511 }
512 elseif (isset($field['field']))
513 {
514 $this->{$field['field']} = $source[$offset];
515 }
516 }
517 }
518
519 return $this;
520 }
521
526 public function toArray(): array
527 {
528 $result = [];
529 $fields = static::mirrorDataEntityFields();
530
531 foreach ($fields as $offset => $field)
532 {
533 if (isset($field['alias']))
534 {
535 continue;
536 }
537 if (
538 isset($field['get'])
539 && ($getter = $field['get'])
540 && is_string($getter)
541 && is_callable([$this, $getter])
542 )
543 {
544 $value = $this->$getter();
545 }
546 else
547 {
548 $value = $this->{$field['field']};
549 }
550
551 if (is_object($value))
552 {
553 if (method_exists($value, 'toArray'))
554 {
555 $value = $value->toArray();
556 }
557 else
558 {
559 continue;
560 }
561 }
562
563 if ($value !== null)
564 {
565 $result[$offset] = $value;
566 }
567 }
568
569 return $result;
570 }
571}
const NOT_FOUND
Definition Error.php:9
addErrors(array $errors)
Definition result.php:98
static createFromTimestamp($timestamp)
Definition datetime.php:246
static tryParse($timeString, $format=null)
Definition datetime.php:260
setDataEntity(EntityObject $dataObject)
initByDataEntity(EntityObject $dataObject)