You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
7.1 KiB

  1. <?php
  2. namespace App\Models;
  3. use Anik\Amqp\Exchange;
  4. use Anik\Amqp\Facades\Amqp;
  5. use App\Events\ModelSaved;
  6. use PhpAmqpLib\Wire\AMQPTable;
  7. use Anik\Amqp\PublishableMessage;
  8. use Illuminate\Http\JsonResponse;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Auth;
  11. use Illuminate\Validation\Validator;
  12. use Illuminate\Database\Eloquent\Collection;
  13. use Illuminate\Validation\ValidationException;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Illuminate\Database\Eloquent\Model as EloquentModel;
  16. class Model extends EloquentModel
  17. {
  18. /**
  19. * Introducing model relationships
  20. *
  21. * @var array
  22. */
  23. protected $fillable_relations = [];
  24. /**
  25. * Models that are ready to change.
  26. *
  27. * @var array
  28. */
  29. protected $filled_relations = [];
  30. /**
  31. * Models that are ready to change.
  32. *
  33. * @var array
  34. */
  35. protected $reportable = [];
  36. protected $dirties = [];
  37. protected $action = null;
  38. public const CREATED = 10;
  39. public const UPDATED = 20;
  40. public const DELETED = 30;
  41. public const RESTORED = 40;
  42. protected static function booted()
  43. {
  44. static::created(function ($model) {
  45. $model->action = static::CREATED;
  46. });
  47. static::updated(function ($model) {
  48. $model->action = static::UPDATED;
  49. });
  50. static::deleted(function ($model) {
  51. $model->action = static::DELETED;
  52. });
  53. }
  54. /**
  55. * @return void
  56. * @throw \Exception
  57. */
  58. public function rules()
  59. {
  60. return [];
  61. }
  62. /**
  63. *
  64. *
  65. * @param array $attributes
  66. * @return void
  67. */
  68. public function validate(array $attributes = null)
  69. {
  70. $attributes = $attributes ?? $this->getAttributes();
  71. /** @var Validator $validator */
  72. $validator = app('validator')->make($attributes, $this->rules());
  73. if ($validator->fails()) {
  74. throw new ValidationException(
  75. $validator,
  76. new JsonResponse($validator->errors()->getMessages(), Response::HTTP_UNPROCESSABLE_ENTITY)
  77. );
  78. }
  79. }
  80. /**
  81. * @return void
  82. */
  83. public function updateRelations()
  84. {
  85. }
  86. /**
  87. * @param string|null $key
  88. * @return void
  89. */
  90. public function getValueOf(?string $key)
  91. {
  92. $values = [];
  93. if ($key && isset($values, $key)) {
  94. return $values[$key];
  95. }
  96. return $values;
  97. }
  98. protected function makeChanges()
  99. {
  100. if (empty($this->reportable)) {
  101. return;
  102. }
  103. $changes = new Collection($this->getDirty());
  104. // fillable * or field
  105. $changes = $changes->filter(function ($value, $key) {
  106. foreach ($this->reportable as $i => $name) {
  107. if ($key === $name) {
  108. return true;
  109. }
  110. }
  111. return false;
  112. });
  113. if (($changes->isEmpty() && $this->action == static::UPDATED)) {
  114. return;
  115. }
  116. return [
  117. 'original' => $this->getOriginal() + $this->getAttributes(),
  118. 'diff' => $changes->toArray(),
  119. ];
  120. // return [
  121. // 'auth' => Auth::id(),
  122. // 'timestamp' => $this->freshTimestamp(),
  123. // 'business' => $this->getValueOf('business_id'),
  124. // 'info' => \request('_business_info')['info'] ?? null,
  125. // 'project' => $this->getValueOf('project_id'),
  126. // 'data' => [
  127. // 'sprint_id' => $this->getValueOf('sprint_id'),
  128. // 'system_id' => $this->getValueOf('system_id'),
  129. // 'workflow_id' => $this->getValueOf('workflow_id'),
  130. // 'status_id' => $this->getValueOf('status_id'),
  131. // 'user_id' => $this->getValueOf('user_id'),
  132. // 'table_name' => $this->getTable(),
  133. // 'crud_id' => $this->action,
  134. // 'original' => $this->getOriginal() + $this->getAttributes(),
  135. // 'diff' => $changes->toArray(),
  136. // ],
  137. // 'from' => env('CONTAINER_NAME'),
  138. // ];
  139. }
  140. protected function report($changes): void
  141. {
  142. if ($this->action == null){
  143. return;
  144. }
  145. $payload = [
  146. 'auth' => Auth::id(),
  147. 'timestamp' => $this->freshTimestamp(),
  148. 'business' => $this->getValueOf('business_id'),
  149. 'info' => \request('_business_info') ?? null,
  150. 'project' => $this->getValueOf('project_id'),
  151. 'data' => [
  152. 'sprint_id' => $this->getValueOf('sprint_id'),
  153. 'system_id' => $this->getValueOf('system_id'),
  154. 'workflow_id' => $this->getValueOf('workflow_id'),
  155. 'status_id' => $this->getValueOf('status_id'),
  156. 'task_id' => $this->getValueOf('task_id'),
  157. 'subject_id' => $this->getValueOf('subject_id'),
  158. 'user_id' => $this->getValueOf('user_id'),
  159. 'table_name' => $this->getTable(),
  160. 'crud_id' => $this->action,
  161. 'original' => $changes['original'] + $this->getOriginal(),
  162. 'diff' => $changes['diff'],
  163. ],
  164. 'from' => env('CONTAINER_NAME'),
  165. ];
  166. // $message = new PublishableMessage(json_encode($payload));
  167. ModelSaved::dispatch(json_encode($payload));
  168. // $routers = [
  169. // "activity_exchange" => ["name" => "activity",],
  170. // "notif_exchange" => ["name" => "notif",],
  171. // "socket_exchange" => ["name" => "socket",],
  172. // ];
  173. //
  174. // foreach ($routers as $exchange => $properties) {
  175. // $message->setProperties(["application_headers" => new AMQPTable($properties)]);
  176. //
  177. // $message->setExchange(new Exchange($exchange));
  178. //
  179. // Amqp::publish($message, "");
  180. // }
  181. }
  182. /**
  183. * @param array $options
  184. * @return void
  185. */
  186. public function save(array $options = [])
  187. {
  188. // The validation function is called first
  189. $this->validate();
  190. // Then, because the relationships are set as attributes in this model
  191. // we pre-enter their names in filled_relation attribute and store
  192. // them in a temporary variable with a loop.
  193. foreach ($this->fillable_relations as $relation) {
  194. $this->filled_relations[$relation] = $this[$relation];
  195. unset($this[$relation]);
  196. }
  197. // all of its action inside one transaction
  198. // so if any of them failed the whole
  199. // process rollbacked
  200. DB::transaction(function () use ($options) {
  201. // report to the activity aggregator
  202. $changes = $this->makeChanges();
  203. // save the model with it's attributes
  204. parent::save($options);
  205. // save the model with it's relationships
  206. $this->updateRelations();
  207. is_array($changes) ? $this->report($changes) : true;
  208. }, 3);
  209. }
  210. public function delete()
  211. {
  212. $changes = $this->makeChanges();
  213. parent::delete();
  214. is_array($changes) ? $this->report($changes) : true;
  215. }
  216. }