Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

274 lines
9.0KB

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controllers;
  4. use App\Models\Customer;
  5. use App\Repositories\CustomerAuditRepository;
  6. use App\Repositories\CustomerRepository;
  7. use App\Repositories\CustomerTypeRepository;
  8. use App\ViewModels\CustomerViewModel;
  9. use Core\Controller;
  10. use Core\Request;
  11. use Core\Response;
  12. class CustomerController extends Controller
  13. {
  14. public function index(): Response
  15. {
  16. $request = Request::capture();
  17. $model = new CustomerViewModel();
  18. $model->saved = $request->input('saved') === '1';
  19. $model->deleted = $request->input('deleted') === '1';
  20. return $this->view('customers.index', [
  21. 'model' => $model,
  22. 'pageTitle' => $model->title,
  23. ]);
  24. }
  25. public function data(): Response
  26. {
  27. $rows = $this->repo()->allWithType();
  28. $data = array_map(static function (array $row): array {
  29. $attrValues = !empty($row['attribute_values'])
  30. ? (json_decode((string) $row['attribute_values'], true) ?? [])
  31. : [];
  32. $customerTypeAttributes = !empty($row['customer_type_attributes'])
  33. ? (json_decode((string) $row['customer_type_attributes'], true) ?? [])
  34. : [];
  35. $summary = implode(', ', array_map(
  36. static fn($k, $v) => "{$k}: {$v}",
  37. array_keys($attrValues),
  38. array_values($attrValues)
  39. ));
  40. return [
  41. 'id' => (int) $row['id'],
  42. 'customer_type_id' => (int) $row['customer_type_id'],
  43. 'customer_type_name' => (string) $row['customer_type_name'],
  44. 'customer_type_attributes' => $customerTypeAttributes,
  45. 'attribute_values' => $attrValues,
  46. 'attributes_summary' => $summary,
  47. 'created_at' => (string) $row['created_at'],
  48. ];
  49. }, $rows);
  50. return $this->json($data);
  51. }
  52. public function create(): Response
  53. {
  54. $model = new CustomerViewModel();
  55. $model->title = 'New Customer';
  56. $model->customerTypes = $this->loadCustomerTypes();
  57. return $this->view('customers.create', [
  58. 'model' => $model,
  59. 'pageTitle' => $model->title,
  60. ]);
  61. }
  62. public function store(): Response
  63. {
  64. $request = Request::capture();
  65. $model = new CustomerViewModel();
  66. $model->title = 'New Customer';
  67. $model->customerTypes = $this->loadCustomerTypes();
  68. [$form, $errors] = $this->validateForm($request, $model->customerTypes);
  69. if (!empty($errors)) {
  70. $model->form = $form;
  71. $model->errors = $errors;
  72. return $this->view('customers.create', [
  73. 'model' => $model,
  74. 'pageTitle' => $model->title,
  75. ]);
  76. }
  77. $customer = new Customer();
  78. $customer->customerTypeId = (int) $form['customer_type_id'];
  79. $customer->attributeValues = $form['attribute_values'];
  80. $this->repo()->create($customer);
  81. $inserted = $this->repo()->findLatestByType($customer->customerTypeId);
  82. if ($inserted !== null) {
  83. $this->auditRepo()->log((int) $inserted['id'], 'I', $this->toAuditFields($inserted), $this->currentUsername());
  84. }
  85. return $this->redirect('/customers?saved=1');
  86. }
  87. public function edit(string $id): Response
  88. {
  89. $row = $this->repo()->findWithType((int) $id);
  90. if ($row === null) {
  91. return $this->redirect('/customers');
  92. }
  93. $storedValues = !empty($row['attribute_values'])
  94. ? (json_decode((string) $row['attribute_values'], true) ?? [])
  95. : [];
  96. $model = new CustomerViewModel();
  97. $model->title = 'Edit Customer';
  98. $model->customer = $row;
  99. $model->saved = Request::capture()->input('saved') === '1';
  100. $model->customerTypes = $this->loadCustomerTypes();
  101. $model->form = [
  102. 'customer_type_id' => (int) $row['customer_type_id'],
  103. 'attribute_values' => $storedValues,
  104. ];
  105. return $this->view('customers.edit', [
  106. 'model' => $model,
  107. 'pageTitle' => $model->title,
  108. ]);
  109. }
  110. public function update(string $id): Response
  111. {
  112. $before = $this->repo()->findWithType((int) $id);
  113. if ($before === null) {
  114. return $this->redirect('/customers');
  115. }
  116. $request = Request::capture();
  117. $model = new CustomerViewModel();
  118. $model->title = 'Edit Customer';
  119. $model->customer = $before;
  120. $model->customerTypes = $this->loadCustomerTypes();
  121. [$form, $errors] = $this->validateForm($request, $model->customerTypes);
  122. if (!empty($errors)) {
  123. $model->form = $form;
  124. $model->errors = $errors;
  125. return $this->view('customers.edit', [
  126. 'model' => $model,
  127. 'pageTitle' => $model->title,
  128. ]);
  129. }
  130. $customer = new Customer();
  131. $customer->id = (int) $id;
  132. $customer->customerTypeId = (int) $form['customer_type_id'];
  133. $customer->attributeValues = $form['attribute_values'];
  134. $this->repo()->update($customer);
  135. $after = $this->repo()->findWithType((int) $id);
  136. $this->auditRepo()->log((int) $id, 'U', [
  137. 'before' => $this->toAuditFields($before),
  138. 'after' => $this->toAuditFields($after ?? []),
  139. ], $this->currentUsername());
  140. return $this->redirect('/customers/' . $id . '/edit?saved=1');
  141. }
  142. public function destroy(string $id): Response
  143. {
  144. $row = $this->repo()->findWithType((int) $id);
  145. if ($row !== null) {
  146. $this->repo()->delete((int) $id);
  147. $this->auditRepo()->log((int) $row['id'], 'D', $this->toAuditFields($row), $this->currentUsername());
  148. }
  149. return $this->redirect('/customers?deleted=1');
  150. }
  151. // ── Helpers ───────────────────────────────────────────────────────────────
  152. private function loadCustomerTypes(): array
  153. {
  154. return array_map(static function (array $type): array {
  155. return [
  156. 'id' => (int) $type['id'],
  157. 'name' => (string) $type['name'],
  158. 'attributes' => json_decode((string) ($type['attributes'] ?? '[]'), true) ?? [],
  159. ];
  160. }, $this->ctRepo()->allOrderedByName());
  161. }
  162. private function attributesForType(int $typeId, array $types): array
  163. {
  164. foreach ($types as $type) {
  165. if ($type['id'] === $typeId) return $type['attributes'];
  166. }
  167. return [];
  168. }
  169. private function validateForm(Request $request, array $customerTypes): array
  170. {
  171. $customerTypeId = (int) $request->input('customer_type_id', 0);
  172. $submittedValues = (array) ($request->input('attribute_values') ?? []);
  173. $errors = [];
  174. if (!verify_csrf_token((string) $request->input('_token', ''))) {
  175. $errors['_token'][] = 'Your form session expired. Please refresh and try again.';
  176. }
  177. if ($customerTypeId === 0) {
  178. $errors['customer_type_id'][] = 'Please select a customer type.';
  179. }
  180. $typeAttributes = $this->attributesForType($customerTypeId, $customerTypes);
  181. $attributeValues = [];
  182. foreach ($typeAttributes as $attr) {
  183. $attributeValues[$attr['name']] = trim((string) ($submittedValues[$attr['name']] ?? ''));
  184. }
  185. return [
  186. ['customer_type_id' => $customerTypeId, 'attribute_values' => $attributeValues],
  187. $errors,
  188. ];
  189. }
  190. private function toAuditFields(array $row): array
  191. {
  192. $attrValues = [];
  193. if (!empty($row['attribute_values'])) {
  194. $raw = $row['attribute_values'];
  195. $attrValues = is_string($raw) ? (json_decode($raw, true) ?? []) : (array) $raw;
  196. }
  197. return [
  198. 'customer_type_id' => (int) ($row['customer_type_id'] ?? 0),
  199. 'customer_type_name' => (string) ($row['customer_type_name'] ?? ''),
  200. 'attribute_values' => $attrValues,
  201. 'created_at' => (string) ($row['created_at'] ?? ''),
  202. 'updated_at' => (string) ($row['updated_at'] ?? ''),
  203. ];
  204. }
  205. private function currentUsername(): string
  206. {
  207. return auth()->user()?->username ?? 'system';
  208. }
  209. private function repo(): CustomerRepository
  210. {
  211. return new CustomerRepository(database());
  212. }
  213. private function auditRepo(): CustomerAuditRepository
  214. {
  215. return new CustomerAuditRepository(database());
  216. }
  217. private function ctRepo(): CustomerTypeRepository
  218. {
  219. return new CustomerTypeRepository(database());
  220. }
  221. }

Powered by TurnKey Linux.