|
- <?php
-
- declare(strict_types=1);
-
- namespace App\Controllers;
-
- use App\Models\JobType;
- use App\Repositories\JobTypeAuditRepository;
- use App\Repositories\JobTypeRepository;
- use App\ViewModels\JobTypeViewModel;
- use Core\Controller;
- use Core\Request;
- use Core\Response;
- use Core\Validator;
-
- class JobTypeController extends Controller
- {
- public function index(): Response
- {
- $request = Request::capture();
- $model = new JobTypeViewModel();
- $model->saved = $request->input('saved') === '1';
- $model->deleted = $request->input('deleted') === '1';
-
- return $this->view('job-types.index', [
- 'model' => $model,
- 'pageTitle' => $model->title,
- ]);
- }
-
- public function data(): Response
- {
- $rows = $this->repo()->allOrderedByName();
-
- $data = array_map(static function (array $row): array {
- $attrs = !empty($row['attributes'])
- ? (json_decode((string) $row['attributes'], true) ?? [])
- : [];
-
- return [
- 'id' => (int) $row['id'],
- 'name' => (string) $row['name'],
- 'attribute_count' => count($attrs),
- 'attributes_summary' => implode(', ', array_column($attrs, 'name')),
- 'created_at' => (string) $row['created_at'],
- ];
- }, $rows);
-
- return $this->json($data);
- }
-
- public function create(): Response
- {
- $model = new JobTypeViewModel();
- $model->title = 'New Job Type';
-
- return $this->view('job-types.create', [
- 'model' => $model,
- 'pageTitle' => $model->title,
- ]);
- }
-
- public function store(): Response
- {
- $request = Request::capture();
- [$form, $errors] = $this->validateForm($request);
-
- if (empty($errors) && $this->repo()->findByName($form['name']) !== null) {
- $errors['name'][] = 'A job type with that name already exists.';
- }
-
- if (!empty($errors)) {
- $model = new JobTypeViewModel();
- $model->title = 'New Job Type';
- $model->form = $form;
- $model->errors = $errors;
-
- return $this->view('job-types.create', [
- 'model' => $model,
- 'pageTitle' => $model->title,
- ]);
- }
-
- $jobType = new JobType();
- $jobType->name = $form['name'];
- $jobType->attributes = $form['attributes'];
-
- $this->repo()->create($jobType);
-
- $inserted = $this->repo()->findByName($form['name']);
- if ($inserted !== null) {
- $this->auditRepo()->log((int) $inserted['id'], 'I', $this->toAuditFields($inserted), $this->currentUsername());
- }
-
- return $this->redirect('/job-types?saved=1');
- }
-
- public function edit(string $id): Response
- {
- $row = $this->repo()->find((int) $id);
-
- if ($row === null) {
- return $this->redirect('/job-types');
- }
-
- $model = new JobTypeViewModel();
- $model->title = 'Edit Job Type';
- $model->jobType = $row;
- $model->saved = Request::capture()->input('saved') === '1';
- $model->form = [
- 'name' => (string) $row['name'],
- 'attributes' => json_decode((string) ($row['attributes'] ?? '[]'), true) ?? [],
- ];
-
- return $this->view('job-types.edit', [
- 'model' => $model,
- 'pageTitle' => $model->title,
- ]);
- }
-
- public function update(string $id): Response
- {
- $row = $this->repo()->find((int) $id);
-
- if ($row === null) {
- return $this->redirect('/job-types');
- }
-
- $request = Request::capture();
- [$form, $errors] = $this->validateForm($request);
-
- if (empty($errors)) {
- $existing = $this->repo()->findByName($form['name']);
- if ($existing !== null && (int) $existing['id'] !== (int) $id) {
- $errors['name'][] = 'A job type with that name already exists.';
- }
- }
-
- if (!empty($errors)) {
- $model = new JobTypeViewModel();
- $model->title = 'Edit Job Type';
- $model->jobType = $row;
- $model->form = $form;
- $model->errors = $errors;
-
- return $this->view('job-types.edit', [
- 'model' => $model,
- 'pageTitle' => $model->title,
- ]);
- }
-
- $before = $row;
- $jobType = new JobType();
- $jobType->id = (int) $id;
- $jobType->name = $form['name'];
- $jobType->attributes = $form['attributes'];
-
- $this->repo()->update($jobType);
-
- $after = $this->repo()->find((int) $id);
- $this->auditRepo()->log((int) $id, 'U', [
- 'before' => $this->toAuditFields($before),
- 'after' => $this->toAuditFields($after ?? []),
- ], $this->currentUsername());
-
- return $this->redirect('/job-types/' . $id . '/edit?saved=1');
- }
-
- public function destroy(string $id): Response
- {
- $row = $this->repo()->find((int) $id);
-
- if ($row !== null) {
- $this->repo()->delete((int) $id);
- $this->auditRepo()->log((int) $row['id'], 'D', $this->toAuditFields($row), $this->currentUsername());
- }
-
- return $this->redirect('/job-types?deleted=1');
- }
-
- // ── Helpers ───────────────────────────────────────────────────────────────
-
- private function toAuditFields(array $row): array
- {
- $attrs = [];
- if (!empty($row['attributes'])) {
- $raw = $row['attributes'];
- $attrs = is_string($raw) ? (json_decode($raw, true) ?? []) : (array) $raw;
- }
-
- return [
- 'name' => (string) ($row['name'] ?? ''),
- 'attributes' => $attrs,
- 'created_at' => (string) ($row['created_at'] ?? ''),
- 'updated_at' => (string) ($row['updated_at'] ?? ''),
- ];
- }
-
- private function currentUsername(): string
- {
- return auth()->user()?->username ?? 'system';
- }
-
- private function validateForm(Request $request): array
- {
- $name = trim((string) $request->input('name', ''));
- $attributeNames = (array) ($request->input('attribute_name') ?? []);
- $attributeTypes = (array) ($request->input('attribute_type') ?? []);
- $attributeOrders = (array) ($request->input('attribute_order') ?? []);
- $errors = [];
-
- if (!verify_csrf_token((string) $request->input('_token', ''))) {
- $errors['_token'][] = 'Your form session expired. Please refresh and try again.';
- }
-
- $errors = array_merge($errors, (new Validator())
- ->required('name', $name, 'Job type name is required.')
- ->maxLength('name', $name, 255, 'Name must be 255 characters or fewer.')
- ->errors());
-
- $attributes = [];
-
- foreach ($attributeNames as $i => $attrName) {
- $attrName = trim((string) $attrName);
- $attrType = trim((string) ($attributeTypes[$i] ?? 'text'));
- if ($attrName === '') continue;
- $attributes[] = [
- 'name' => $attrName,
- 'type' => in_array($attrType, ['text', 'number', 'date', 'boolean'], true) ? $attrType : 'text',
- 'order' => isset($attributeOrders[$i]) && (string) $attributeOrders[$i] !== ''
- ? max(1, (int) $attributeOrders[$i])
- : count($attributes) + 1,
- ];
- }
-
- usort($attributes, static fn(array $a, array $b): int => $a['order'] <=> $b['order']);
- foreach ($attributes as $seq => &$attr) {
- $attr['order'] = $seq + 1;
- }
- unset($attr);
-
- return [['name' => $name, 'attributes' => $attributes], $errors];
- }
-
- private function repo(): JobTypeRepository
- {
- return new JobTypeRepository(database());
- }
-
- private function auditRepo(): JobTypeAuditRepository
- {
- return new JobTypeAuditRepository(database());
- }
- }
|