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.

254 lines
7.0 KiB

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