DataModel.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. /**
  3. * This file is part of the ForkBB <https://github.com/forkbb>.
  4. *
  5. * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
  6. * @license The MIT License (MIT)
  7. */
  8. declare(strict_types=1);
  9. namespace ForkBB\Models;
  10. use ForkBB\Models\Model;
  11. class DataModel extends Model
  12. {
  13. /**
  14. * Массив флагов измененных свойств модели
  15. */
  16. protected array $zModFlags = [];
  17. /**
  18. * Массив состояний отслеживания изменений в свойствах модели
  19. */
  20. protected array $zTrackFlags = [];
  21. /**
  22. * Устанавливает значения для свойств
  23. * Сбрасывает вычисленные свойства
  24. * Флаги модификации свойст сброшены
  25. */
  26. public function setAttrs(array $attrs): Model
  27. {
  28. $this->zModFlags = [];
  29. $this->zTrackFlags = [];
  30. return parent::setAttrs($attrs);
  31. }
  32. /**
  33. * Перезаписывает свойства модели
  34. * Флаги модификации свойств сбрасываются/устанавливаются в зависимости от второго параметра
  35. */
  36. public function replAttrs(array $attrs, bool $setFlags = false): DataModel
  37. {
  38. foreach ($attrs as $name => $value) {
  39. $this->__set($name, $value);
  40. if (! $setFlags) {
  41. unset($this->zModFlags[$name]);
  42. }
  43. }
  44. return $this;
  45. }
  46. /**
  47. * Возвращает массив имен измененных свойств модели
  48. */
  49. public function getModified(): array
  50. {
  51. return \array_keys($this->zModFlags);
  52. }
  53. /**
  54. * Возвращает модифицировано ли свойство модели
  55. */
  56. public function isModified(string $name): bool
  57. {
  58. return isset($this->zModFlags[$name]);
  59. }
  60. /**
  61. * Обнуляет массив флагов измененных свойств модели
  62. */
  63. public function resModified(): void
  64. {
  65. $this->zModFlags = [];
  66. $this->zTrackFlags = [];
  67. }
  68. /**
  69. * Устанавливает значение для свойства
  70. */
  71. public function __set(string $name, mixed $value): void
  72. {
  73. // без отслеживания
  74. if (\str_starts_with($name, '__')) {
  75. $track = null;
  76. $name = \substr($name, 2);
  77. // с отслеживанием
  78. } else {
  79. $track = false;
  80. if (\array_key_exists($name, $this->zAttrs)) {
  81. $track = true;
  82. $old = $this->zAttrs[$name];
  83. // fix
  84. if (
  85. \is_int($value)
  86. && \is_numeric($old)
  87. && \is_int(0 + $old)
  88. ) {
  89. $old = (int) $old;
  90. }
  91. }
  92. }
  93. $this->zTrackFlags[$name] = $track;
  94. parent::__set($name, $value);
  95. unset($this->zTrackFlags[$name]);
  96. if (null === $track) {
  97. return;
  98. }
  99. if (
  100. (
  101. ! $track
  102. && \array_key_exists($name, $this->zAttrs)
  103. )
  104. || (
  105. $track
  106. && $old !== $this->zAttrs[$name]
  107. )
  108. ) {
  109. $this->zModFlags[$name] = true;
  110. if (isset($this->zDepend[$name])) {
  111. foreach ($this->zDepend[$name] as $dependent) {
  112. $this->zModFlags[$dependent] = true; //???? может только физические свойства менять?
  113. }
  114. }
  115. }
  116. }
  117. /**
  118. * Возвращает значение свойства
  119. */
  120. public function __get(string $name): mixed
  121. {
  122. // без вычисления
  123. if (\str_starts_with($name, '__')) {
  124. return $this->getAttr(\substr($name, 2));
  125. // с вычислениями
  126. } else {
  127. return parent::__get($name);
  128. }
  129. }
  130. /**
  131. * Удаляет свойство ????
  132. */
  133. public function __unset(string $name): void
  134. {
  135. $this->zModFlags[$name] = false;
  136. parent::__unset($name);
  137. }
  138. }