選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

267 行
10KB

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controllers;
  4. use App\Repositories\HouseholdRepository;
  5. use App\Repositories\HouseholderNameRepository;
  6. use App\Repositories\TerritoryRepository;
  7. use Core\Controller;
  8. use Core\Pagination;
  9. use Core\Request;
  10. use Core\Response;
  11. use Core\Validator;
  12. class HouseholdController extends Controller
  13. {
  14. public function index(): Response
  15. {
  16. if ($redirect = $this->requireAuth()) {
  17. return $redirect;
  18. }
  19. $request = Request::capture();
  20. $search = (string) ($request->input('search') ?? '');
  21. $territoryId = (string) ($request->input('territory_id') ?? '');
  22. $doNotCall = (string) ($request->input('do_not_call') ?? '');
  23. $page = max(1, (int) ($request->input('page') ?? 1));
  24. $perPage = 20;
  25. $repo = new HouseholdRepository(database());
  26. $total = $repo->countAll($search, $territoryId, $doNotCall);
  27. $pagination = new Pagination($total, $page, $perPage);
  28. $households = $repo->findPaged($page, $perPage, $search, $territoryId, $doNotCall);
  29. $territories = (new TerritoryRepository(database()))->allOrdered();
  30. return $this->view('households.index', [
  31. 'pageTitle' => 'Households',
  32. 'households' => $households,
  33. 'territories' => $territories,
  34. 'search' => $search,
  35. 'territoryId' => $territoryId,
  36. 'doNotCall' => $doNotCall,
  37. 'pagination' => $pagination,
  38. ]);
  39. }
  40. public function show(int|string $id): Response
  41. {
  42. if ($redirect = $this->requireAuth()) {
  43. return $redirect;
  44. }
  45. $household = (new HouseholdRepository(database()))->findWithTerritory((int) $id);
  46. if (!$household) {
  47. return Response::notFound('Household not found.');
  48. }
  49. $names = (new HouseholderNameRepository(database()))->findAllByHousehold((int) $id);
  50. $maps = maps_config();
  51. return $this->view('households.show', [
  52. 'pageTitle' => e($household['address']),
  53. 'household' => $household,
  54. 'names' => $names,
  55. 'maps' => $maps,
  56. ]);
  57. }
  58. public function create(): Response
  59. {
  60. if ($redirect = $this->requireAuth()) {
  61. return $redirect;
  62. }
  63. $request = Request::capture();
  64. $territories = (new TerritoryRepository(database()))->allOrdered();
  65. return $this->view('households.create', [
  66. 'pageTitle' => 'New Household',
  67. 'territories' => $territories,
  68. 'defaultTerritoryId' => (string) ($request->input('territory_id') ?? ''),
  69. 'errors' => [],
  70. 'old' => [],
  71. ]);
  72. }
  73. public function store(): Response
  74. {
  75. if ($redirect = $this->requireAuth()) {
  76. return $redirect;
  77. }
  78. $request = Request::capture();
  79. $territories = (new TerritoryRepository(database()))->allOrdered();
  80. if (!verify_csrf_token($request->input('_token'))) {
  81. return $this->view('households.create', [
  82. 'pageTitle' => 'New Household',
  83. 'territories' => $territories,
  84. 'defaultTerritoryId' => '',
  85. 'errors' => ['_token' => ['Invalid request. Please try again.']],
  86. 'old' => $request->all(),
  87. ]);
  88. }
  89. $fields = $this->extractFields($request);
  90. $validator = (new Validator())
  91. ->required('territory_id', $fields['territory_id'], 'Territory is required.')
  92. ->required('address', $fields['address'], 'Address is required.')
  93. ->maxLength('address', $fields['address'], 255)
  94. ->optionalNumeric('street_number', $fields['street_number'])
  95. ->optionalNumeric('latitude', $fields['latitude'], 'Latitude must be a number.')
  96. ->optionalNumeric('longitude', $fields['longitude'], 'Longitude must be a number.');
  97. if ($validator->fails()) {
  98. return $this->view('households.create', [
  99. 'pageTitle' => 'New Household',
  100. 'territories' => $territories,
  101. 'defaultTerritoryId' => $fields['territory_id'],
  102. 'errors' => $validator->errors(),
  103. 'old' => $request->all(),
  104. ]);
  105. }
  106. $now = date('Y-m-d H:i:s');
  107. database()->execute(
  108. 'INSERT INTO households
  109. (territory_id, address, street_number, street_name, latitude, longitude,
  110. is_business, do_not_call, do_not_call_date, do_not_call_notes,
  111. do_not_call_private_notes, created_at, updated_at)
  112. VALUES
  113. (:territory_id, :address, :street_number, :street_name, :latitude, :longitude,
  114. :is_business, :do_not_call, :do_not_call_date, :do_not_call_notes,
  115. :do_not_call_private_notes, :now, :now)',
  116. array_merge($fields, ['now' => $now])
  117. );
  118. flash('success', 'Household created.');
  119. return $this->redirect('/households');
  120. }
  121. public function edit(int|string $id): Response
  122. {
  123. if ($redirect = $this->requireAuth()) {
  124. return $redirect;
  125. }
  126. $household = (new HouseholdRepository(database()))->find((int) $id);
  127. if (!$household) {
  128. return Response::notFound('Household not found.');
  129. }
  130. $territories = (new TerritoryRepository(database()))->allOrdered();
  131. return $this->view('households.edit', [
  132. 'pageTitle' => 'Edit Household',
  133. 'household' => $household,
  134. 'territories' => $territories,
  135. 'errors' => [],
  136. ]);
  137. }
  138. public function update(int|string $id): Response
  139. {
  140. if ($redirect = $this->requireAuth()) {
  141. return $redirect;
  142. }
  143. $request = Request::capture();
  144. $household = (new HouseholdRepository(database()))->find((int) $id);
  145. if (!$household) {
  146. return Response::notFound('Household not found.');
  147. }
  148. if (!verify_csrf_token($request->input('_token'))) {
  149. flash('error', 'Invalid request.');
  150. return $this->redirect('/households/' . $id . '/edit');
  151. }
  152. $fields = $this->extractFields($request);
  153. $validator = (new Validator())
  154. ->required('territory_id', $fields['territory_id'], 'Territory is required.')
  155. ->required('address', $fields['address'], 'Address is required.')
  156. ->maxLength('address', $fields['address'], 255)
  157. ->optionalNumeric('street_number', $fields['street_number'])
  158. ->optionalNumeric('latitude', $fields['latitude'], 'Latitude must be a number.')
  159. ->optionalNumeric('longitude', $fields['longitude'], 'Longitude must be a number.');
  160. $territories = (new TerritoryRepository(database()))->allOrdered();
  161. if ($validator->fails()) {
  162. return $this->view('households.edit', [
  163. 'pageTitle' => 'Edit Household',
  164. 'household' => array_merge($household, $fields),
  165. 'territories' => $territories,
  166. 'errors' => $validator->errors(),
  167. ]);
  168. }
  169. database()->execute(
  170. 'UPDATE households SET
  171. territory_id = :territory_id, address = :address,
  172. street_number = :street_number, street_name = :street_name,
  173. latitude = :latitude, longitude = :longitude,
  174. is_business = :is_business, do_not_call = :do_not_call,
  175. do_not_call_date = :do_not_call_date, do_not_call_notes = :do_not_call_notes,
  176. do_not_call_private_notes = :do_not_call_private_notes,
  177. updated_at = :now
  178. WHERE id = :id',
  179. array_merge($fields, ['now' => date('Y-m-d H:i:s'), 'id' => $id])
  180. );
  181. flash('success', 'Household updated.');
  182. return $this->redirect('/households/' . $id);
  183. }
  184. public function delete(int|string $id): Response
  185. {
  186. if ($redirect = $this->requireAuth()) {
  187. return $redirect;
  188. }
  189. $request = Request::capture();
  190. $household = (new HouseholdRepository(database()))->find((int) $id);
  191. if (!$household) {
  192. return Response::notFound('Household not found.');
  193. }
  194. if (!verify_csrf_token($request->input('_token'))) {
  195. flash('error', 'Invalid request.');
  196. return $this->redirect('/households');
  197. }
  198. database()->execute('DELETE FROM householder_names WHERE household_id = :id', ['id' => $id]);
  199. database()->execute('DELETE FROM households WHERE id = :id', ['id' => $id]);
  200. flash('success', 'Household deleted.');
  201. return $this->redirect('/households');
  202. }
  203. /** @return array<string,mixed> */
  204. private function extractFields(Request $request): array
  205. {
  206. $doNotCall = (bool) $request->input('do_not_call');
  207. return [
  208. 'territory_id' => (string) ($request->input('territory_id') ?? ''),
  209. 'address' => trim((string) ($request->input('address') ?? '')),
  210. 'street_number' => $request->input('street_number') !== '' ? $request->input('street_number') : null,
  211. 'street_name' => trim((string) ($request->input('street_name') ?? '')),
  212. 'latitude' => $request->input('latitude') !== '' ? $request->input('latitude') : null,
  213. 'longitude' => $request->input('longitude') !== '' ? $request->input('longitude') : null,
  214. 'is_business' => (int) (bool) $request->input('is_business'),
  215. 'do_not_call' => (int) $doNotCall,
  216. 'do_not_call_date' => $doNotCall ? (trim((string) ($request->input('do_not_call_date') ?? '')) ?: null) : null,
  217. 'do_not_call_notes' => trim((string) ($request->input('do_not_call_notes') ?? '')),
  218. 'do_not_call_private_notes' => trim((string) ($request->input('do_not_call_private_notes') ?? '')),
  219. ];
  220. }
  221. }

Powered by TurnKey Linux.