Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

255 строки
8.2KB

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controllers;
  4. use App\Models\JobType;
  5. use App\Repositories\JobTypeAuditRepository;
  6. use App\Repositories\JobTypeRepository;
  7. use App\ViewModels\JobTypeViewModel;
  8. use Core\Controller;
  9. use Core\Request;
  10. use Core\Response;
  11. use Core\Validator;
  12. class JobTypeController extends Controller
  13. {
  14. public function index(): Response
  15. {
  16. $request = Request::capture();
  17. $model = new JobTypeViewModel();
  18. $model->saved = $request->input('saved') === '1';
  19. $model->deleted = $request->input('deleted') === '1';
  20. return $this->view('job-types.index', [
  21. 'model' => $model,
  22. 'pageTitle' => $model->title,
  23. ]);
  24. }
  25. public function data(): Response
  26. {
  27. $rows = $this->repo()->allOrderedByName();
  28. $data = array_map(static function (array $row): array {
  29. $attrs = !empty($row['attributes'])
  30. ? (json_decode((string) $row['attributes'], true) ?? [])
  31. : [];
  32. return [
  33. 'id' => (int) $row['id'],
  34. 'name' => (string) $row['name'],
  35. 'attribute_count' => count($attrs),
  36. 'attributes_summary' => implode(', ', array_column($attrs, 'name')),
  37. 'created_at' => (string) $row['created_at'],
  38. ];
  39. }, $rows);
  40. return $this->json($data);
  41. }
  42. public function create(): Response
  43. {
  44. $model = new JobTypeViewModel();
  45. $model->title = 'New Job Type';
  46. return $this->view('job-types.create', [
  47. 'model' => $model,
  48. 'pageTitle' => $model->title,
  49. ]);
  50. }
  51. public function store(): Response
  52. {
  53. $request = Request::capture();
  54. [$form, $errors] = $this->validateForm($request);
  55. if (empty($errors) && $this->repo()->findByName($form['name']) !== null) {
  56. $errors['name'][] = 'A job type with that name already exists.';
  57. }
  58. if (!empty($errors)) {
  59. $model = new JobTypeViewModel();
  60. $model->title = 'New Job Type';
  61. $model->form = $form;
  62. $model->errors = $errors;
  63. return $this->view('job-types.create', [
  64. 'model' => $model,
  65. 'pageTitle' => $model->title,
  66. ]);
  67. }
  68. $jobType = new JobType();
  69. $jobType->name = $form['name'];
  70. $jobType->attributes = $form['attributes'];
  71. $this->repo()->create($jobType);
  72. $inserted = $this->repo()->findByName($form['name']);
  73. if ($inserted !== null) {
  74. $this->auditRepo()->log((int) $inserted['id'], 'I', $this->toAuditFields($inserted), $this->currentUsername());
  75. }
  76. return $this->redirect('/job-types?saved=1');
  77. }
  78. public function edit(string $id): Response
  79. {
  80. $row = $this->repo()->find((int) $id);
  81. if ($row === null) {
  82. return $this->redirect('/job-types');
  83. }
  84. $model = new JobTypeViewModel();
  85. $model->title = 'Edit Job Type';
  86. $model->jobType = $row;
  87. $model->saved = Request::capture()->input('saved') === '1';
  88. $model->form = [
  89. 'name' => (string) $row['name'],
  90. 'attributes' => json_decode((string) ($row['attributes'] ?? '[]'), true) ?? [],
  91. ];
  92. return $this->view('job-types.edit', [
  93. 'model' => $model,
  94. 'pageTitle' => $model->title,
  95. ]);
  96. }
  97. public function update(string $id): Response
  98. {
  99. $row = $this->repo()->find((int) $id);
  100. if ($row === null) {
  101. return $this->redirect('/job-types');
  102. }
  103. $request = Request::capture();
  104. [$form, $errors] = $this->validateForm($request);
  105. if (empty($errors)) {
  106. $existing = $this->repo()->findByName($form['name']);
  107. if ($existing !== null && (int) $existing['id'] !== (int) $id) {
  108. $errors['name'][] = 'A job type with that name already exists.';
  109. }
  110. }
  111. if (!empty($errors)) {
  112. $model = new JobTypeViewModel();
  113. $model->title = 'Edit Job Type';
  114. $model->jobType = $row;
  115. $model->form = $form;
  116. $model->errors = $errors;
  117. return $this->view('job-types.edit', [
  118. 'model' => $model,
  119. 'pageTitle' => $model->title,
  120. ]);
  121. }
  122. $before = $row;
  123. $jobType = new JobType();
  124. $jobType->id = (int) $id;
  125. $jobType->name = $form['name'];
  126. $jobType->attributes = $form['attributes'];
  127. $this->repo()->update($jobType);
  128. $after = $this->repo()->find((int) $id);
  129. $this->auditRepo()->log((int) $id, 'U', [
  130. 'before' => $this->toAuditFields($before),
  131. 'after' => $this->toAuditFields($after ?? []),
  132. ], $this->currentUsername());
  133. return $this->redirect('/job-types/' . $id . '/edit?saved=1');
  134. }
  135. public function destroy(string $id): Response
  136. {
  137. $row = $this->repo()->find((int) $id);
  138. if ($row !== null) {
  139. $this->repo()->delete((int) $id);
  140. $this->auditRepo()->log((int) $row['id'], 'D', $this->toAuditFields($row), $this->currentUsername());
  141. }
  142. return $this->redirect('/job-types?deleted=1');
  143. }
  144. // ── Helpers ───────────────────────────────────────────────────────────────
  145. private function toAuditFields(array $row): array
  146. {
  147. $attrs = [];
  148. if (!empty($row['attributes'])) {
  149. $raw = $row['attributes'];
  150. $attrs = is_string($raw) ? (json_decode($raw, true) ?? []) : (array) $raw;
  151. }
  152. return [
  153. 'name' => (string) ($row['name'] ?? ''),
  154. 'attributes' => $attrs,
  155. 'created_at' => (string) ($row['created_at'] ?? ''),
  156. 'updated_at' => (string) ($row['updated_at'] ?? ''),
  157. ];
  158. }
  159. private function currentUsername(): string
  160. {
  161. return auth()->user()?->username ?? 'system';
  162. }
  163. private function validateForm(Request $request): array
  164. {
  165. $name = trim((string) $request->input('name', ''));
  166. $attributeNames = (array) ($request->input('attribute_name') ?? []);
  167. $attributeTypes = (array) ($request->input('attribute_type') ?? []);
  168. $attributeOrders = (array) ($request->input('attribute_order') ?? []);
  169. $errors = [];
  170. if (!verify_csrf_token((string) $request->input('_token', ''))) {
  171. $errors['_token'][] = 'Your form session expired. Please refresh and try again.';
  172. }
  173. $errors = array_merge($errors, (new Validator())
  174. ->required('name', $name, 'Job type name is required.')
  175. ->maxLength('name', $name, 255, 'Name must be 255 characters or fewer.')
  176. ->errors());
  177. $attributes = [];
  178. foreach ($attributeNames as $i => $attrName) {
  179. $attrName = trim((string) $attrName);
  180. $attrType = trim((string) ($attributeTypes[$i] ?? 'text'));
  181. if ($attrName === '') continue;
  182. $attributes[] = [
  183. 'name' => $attrName,
  184. 'type' => in_array($attrType, ['text', 'number', 'date', 'boolean'], true) ? $attrType : 'text',
  185. 'order' => isset($attributeOrders[$i]) && (string) $attributeOrders[$i] !== ''
  186. ? max(1, (int) $attributeOrders[$i])
  187. : count($attributes) + 1,
  188. ];
  189. }
  190. usort($attributes, static fn(array $a, array $b): int => $a['order'] <=> $b['order']);
  191. foreach ($attributes as $seq => &$attr) {
  192. $attr['order'] = $seq + 1;
  193. }
  194. unset($attr);
  195. return [['name' => $name, 'attributes' => $attributes], $errors];
  196. }
  197. private function repo(): JobTypeRepository
  198. {
  199. return new JobTypeRepository(database());
  200. }
  201. private function auditRepo(): JobTypeAuditRepository
  202. {
  203. return new JobTypeAuditRepository(database());
  204. }
  205. }

Powered by TurnKey Linux.