|
- <?php
-
- declare(strict_types=1);
-
- namespace App\Controllers;
-
- use App\Repositories\HouseholdRepository;
- use App\Repositories\HouseholderNameRepository;
- use App\Repositories\TerritoryRepository;
- use Core\Controller;
- use Core\Pagination;
- use Core\Request;
- use Core\Response;
- use Core\Validator;
-
- class HouseholdController extends Controller
- {
- public function index(): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $request = Request::capture();
- $search = (string) ($request->input('search') ?? '');
- $territoryId = (string) ($request->input('territory_id') ?? '');
- $doNotCall = (string) ($request->input('do_not_call') ?? '');
- $page = max(1, (int) ($request->input('page') ?? 1));
- $perPage = 20;
-
- $repo = new HouseholdRepository(database());
- $total = $repo->countAll($search, $territoryId, $doNotCall);
- $pagination = new Pagination($total, $page, $perPage);
- $households = $repo->findPaged($page, $perPage, $search, $territoryId, $doNotCall);
- $territories = (new TerritoryRepository(database()))->allOrdered();
-
- return $this->view('households.index', [
- 'pageTitle' => 'Households',
- 'households' => $households,
- 'territories' => $territories,
- 'search' => $search,
- 'territoryId' => $territoryId,
- 'doNotCall' => $doNotCall,
- 'pagination' => $pagination,
- ]);
- }
-
- public function show(int|string $id): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $household = (new HouseholdRepository(database()))->findWithTerritory((int) $id);
-
- if (!$household) {
- return Response::notFound('Household not found.');
- }
-
- $names = (new HouseholderNameRepository(database()))->findAllByHousehold((int) $id);
- $maps = maps_config();
-
- return $this->view('households.show', [
- 'pageTitle' => e($household['address']),
- 'household' => $household,
- 'names' => $names,
- 'maps' => $maps,
- ]);
- }
-
- public function create(): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $request = Request::capture();
- $territories = (new TerritoryRepository(database()))->allOrdered();
-
- return $this->view('households.create', [
- 'pageTitle' => 'New Household',
- 'territories' => $territories,
- 'defaultTerritoryId' => (string) ($request->input('territory_id') ?? ''),
- 'errors' => [],
- 'old' => [],
- ]);
- }
-
- public function store(): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $request = Request::capture();
- $territories = (new TerritoryRepository(database()))->allOrdered();
-
- if (!verify_csrf_token($request->input('_token'))) {
- return $this->view('households.create', [
- 'pageTitle' => 'New Household',
- 'territories' => $territories,
- 'defaultTerritoryId' => '',
- 'errors' => ['_token' => ['Invalid request. Please try again.']],
- 'old' => $request->all(),
- ]);
- }
-
- $fields = $this->extractFields($request);
-
- $validator = (new Validator())
- ->required('territory_id', $fields['territory_id'], 'Territory is required.')
- ->required('address', $fields['address'], 'Address is required.')
- ->maxLength('address', $fields['address'], 255)
- ->optionalNumeric('street_number', $fields['street_number'])
- ->optionalNumeric('latitude', $fields['latitude'], 'Latitude must be a number.')
- ->optionalNumeric('longitude', $fields['longitude'], 'Longitude must be a number.');
-
- if ($validator->fails()) {
- return $this->view('households.create', [
- 'pageTitle' => 'New Household',
- 'territories' => $territories,
- 'defaultTerritoryId' => $fields['territory_id'],
- 'errors' => $validator->errors(),
- 'old' => $request->all(),
- ]);
- }
-
- $now = date('Y-m-d H:i:s');
- database()->execute(
- 'INSERT INTO households
- (territory_id, address, street_number, street_name, latitude, longitude,
- is_business, do_not_call, do_not_call_date, do_not_call_notes,
- do_not_call_private_notes, created_at, updated_at)
- VALUES
- (:territory_id, :address, :street_number, :street_name, :latitude, :longitude,
- :is_business, :do_not_call, :do_not_call_date, :do_not_call_notes,
- :do_not_call_private_notes, :now, :now)',
- array_merge($fields, ['now' => $now])
- );
-
- flash('success', 'Household created.');
- return $this->redirect('/households');
- }
-
- public function edit(int|string $id): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $household = (new HouseholdRepository(database()))->find((int) $id);
-
- if (!$household) {
- return Response::notFound('Household not found.');
- }
-
- $territories = (new TerritoryRepository(database()))->allOrdered();
-
- return $this->view('households.edit', [
- 'pageTitle' => 'Edit Household',
- 'household' => $household,
- 'territories' => $territories,
- 'errors' => [],
- ]);
- }
-
- public function update(int|string $id): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $request = Request::capture();
- $household = (new HouseholdRepository(database()))->find((int) $id);
-
- if (!$household) {
- return Response::notFound('Household not found.');
- }
-
- if (!verify_csrf_token($request->input('_token'))) {
- flash('error', 'Invalid request.');
- return $this->redirect('/households/' . $id . '/edit');
- }
-
- $fields = $this->extractFields($request);
- $validator = (new Validator())
- ->required('territory_id', $fields['territory_id'], 'Territory is required.')
- ->required('address', $fields['address'], 'Address is required.')
- ->maxLength('address', $fields['address'], 255)
- ->optionalNumeric('street_number', $fields['street_number'])
- ->optionalNumeric('latitude', $fields['latitude'], 'Latitude must be a number.')
- ->optionalNumeric('longitude', $fields['longitude'], 'Longitude must be a number.');
-
- $territories = (new TerritoryRepository(database()))->allOrdered();
-
- if ($validator->fails()) {
- return $this->view('households.edit', [
- 'pageTitle' => 'Edit Household',
- 'household' => array_merge($household, $fields),
- 'territories' => $territories,
- 'errors' => $validator->errors(),
- ]);
- }
-
- database()->execute(
- 'UPDATE households SET
- territory_id = :territory_id, address = :address,
- street_number = :street_number, street_name = :street_name,
- latitude = :latitude, longitude = :longitude,
- is_business = :is_business, do_not_call = :do_not_call,
- do_not_call_date = :do_not_call_date, do_not_call_notes = :do_not_call_notes,
- do_not_call_private_notes = :do_not_call_private_notes,
- updated_at = :now
- WHERE id = :id',
- array_merge($fields, ['now' => date('Y-m-d H:i:s'), 'id' => $id])
- );
-
- flash('success', 'Household updated.');
- return $this->redirect('/households/' . $id);
- }
-
- public function delete(int|string $id): Response
- {
- if ($redirect = $this->requireAuth()) {
- return $redirect;
- }
-
- $request = Request::capture();
- $household = (new HouseholdRepository(database()))->find((int) $id);
-
- if (!$household) {
- return Response::notFound('Household not found.');
- }
-
- if (!verify_csrf_token($request->input('_token'))) {
- flash('error', 'Invalid request.');
- return $this->redirect('/households');
- }
-
- database()->execute('DELETE FROM householder_names WHERE household_id = :id', ['id' => $id]);
- database()->execute('DELETE FROM households WHERE id = :id', ['id' => $id]);
-
- flash('success', 'Household deleted.');
- return $this->redirect('/households');
- }
-
- /** @return array<string,mixed> */
- private function extractFields(Request $request): array
- {
- $doNotCall = (bool) $request->input('do_not_call');
-
- return [
- 'territory_id' => (string) ($request->input('territory_id') ?? ''),
- 'address' => trim((string) ($request->input('address') ?? '')),
- 'street_number' => $request->input('street_number') !== '' ? $request->input('street_number') : null,
- 'street_name' => trim((string) ($request->input('street_name') ?? '')),
- 'latitude' => $request->input('latitude') !== '' ? $request->input('latitude') : null,
- 'longitude' => $request->input('longitude') !== '' ? $request->input('longitude') : null,
- 'is_business' => (int) (bool) $request->input('is_business'),
- 'do_not_call' => (int) $doNotCall,
- 'do_not_call_date' => $doNotCall ? (trim((string) ($request->input('do_not_call_date') ?? '')) ?: null) : null,
- 'do_not_call_notes' => trim((string) ($request->input('do_not_call_notes') ?? '')),
- 'do_not_call_private_notes' => trim((string) ($request->input('do_not_call_private_notes') ?? '')),
- ];
- }
- }
|