buildSearchQuery($request); $persons = $this->paginateAndLoadRelations($query, $request); return response()->json([ 'success' => true, 'data' => new PersonCollection($persons), 'message' => 'Public search results retrieved successfully' ]); } catch (Exception $e) { return response()->json([ 'success' => false, 'message' => 'Failed to retrieve search results', 'error' => $e->getMessage() ], 500); } } /** * Build the search query with all filters applied * * @param Request $request * @return Builder */ private function buildSearchQuery(Request $request): Builder { $query = Person::query(); $useOrConditions = $this->shouldUseOrConditions($request); // Apply basic filters (firstName, lastName, etc.) $this->applyBasicFilters($query, $request, $useOrConditions); // Apply relation-based filters $this->applyYearOfArrivalFilter($query, $request); $this->applyAgeAtMigrationFilter($query, $request); $this->applySettlementLocationFilter($query, $request); return $query; } /** * Determine if OR logic should be used between filters * * @param Request $request * @return bool */ private function shouldUseOrConditions(Request $request): bool { $exactMatch = $request->boolean('exactMatch'); $useOrLogic = $request->boolean('useOrLogic'); return $useOrLogic || $exactMatch; } /** * Apply filters for fields in the Person table * * @param Builder $query * @param Request $request * @param bool $useOrConditions * @return void */ private function applyBasicFilters(Builder $query, Request $request, bool $useOrConditions): void { $filters = $this->collectBasicFilters($request); if (empty($filters)) { return; } if ($useOrConditions) { $this->applyFiltersWithOrLogic($query, $filters); } else { $this->applyFiltersWithAndLogic($query, $filters); } } /** * Collect basic filters from the request * * @param Request $request * @return array */ private function collectBasicFilters(Request $request): array { $exactMatch = $request->boolean('exactMatch'); $filters = []; $filterFields = [ 'id_card_no' => 'id_card_no', 'firstName' => 'christian_name', 'lastName' => 'surname', 'regionOfOrigin' => 'place_of_birth' ]; foreach ($filterFields as $requestKey => $dbField) { if ($request->has($requestKey) && $request->input($requestKey) !== 'all') { $value = $request->input($requestKey); if ($exactMatch) { // For exact matching, use raw query with BINARY for strict case-sensitive matching $filters[] = [$dbField, 'raw', $value]; } else { // For partial matching, use standard LIKE with wildcards $filters[] = [$dbField, 'LIKE', "%{$value}%"]; } } } return $filters; } /** * Apply filters using OR logic * * @param Builder $query * @param array $filters * @return void */ private function applyFiltersWithOrLogic(Builder $query, array $filters): void { $query->where(function ($q) use ($filters) { foreach ($filters as $index => $filter) { $method = $index === 0 ? 'where' : 'orWhere'; if ($filter[1] === 'raw') { // Handle raw exact matching (case-sensitive) $field = $filter[0]; $value = $filter[2]; $q->whereRaw("BINARY {$field} = ?", [$value]); } else { // Handle standard operators $q->{$method}($filter[0], $filter[1], $filter[2]); } } }); } /** * Apply filters using AND logic * * @param Builder $query * @param array $filters * @return void */ private function applyFiltersWithAndLogic(Builder $query, array $filters): void { foreach ($filters as $filter) { if ($filter[1] === 'raw') { // Handle raw exact matching (case-sensitive) $field = $filter[0]; $value = $filter[2]; $query->whereRaw("BINARY {$field} = ?", [$value]); } else { // Handle standard operators $query->where($filter[0], $filter[1], $filter[2]); } } } /** * Filter by Year of Arrival * * @param Builder $query * @param Request $request * @return void */ private function applyYearOfArrivalFilter(Builder $query, Request $request): void { if ($request->has('yearOfArrival') && $request->yearOfArrival !== 'all') { $year = $request->yearOfArrival; $query->whereHas('migration', function (Builder $subQuery) use ($year) { $subQuery->whereYear('date_of_arrival_aus', $year) ->orWhereYear('date_of_arrival_nt', $year); }); } } /** * Filter by Age at Migration * * @param Builder $query * @param Request $request * @return void */ private function applyAgeAtMigrationFilter(Builder $query, Request $request): void { if ($request->has('ageAtMigration') && $request->ageAtMigration !== 'all') { $ageAtMigration = (int) $request->ageAtMigration; $query->whereHas('migration', function (Builder $subQuery) use ($ageAtMigration) { $subQuery->whereRaw('YEAR(date_of_arrival_aus) - YEAR(person.date_of_birth) = ?', [$ageAtMigration]) ->orWhereRaw('YEAR(date_of_arrival_nt) - YEAR(person.date_of_birth) = ?', [$ageAtMigration]); }); } } /** * Filter by Settlement Location * * @param Builder $query * @param Request $request * @return void */ private function applySettlementLocationFilter(Builder $query, Request $request): void { if ($request->has('settlementLocation') && $request->settlementLocation !== 'all') { $location = $request->settlementLocation; $query->whereHas('residence', function (Builder $subQuery) use ($location) { $subQuery->where('town_or_city', 'LIKE', "%{$location}%"); }); } } /** * Paginate results and load related models * * @param Builder $query * @param Request $request * @return \Illuminate\Pagination\LengthAwarePaginator */ private function paginateAndLoadRelations(Builder $query, Request $request): \Illuminate\Pagination\LengthAwarePaginator { $perPage = $request->input('per_page', 10); $persons = $query->paginate($perPage); // Eager load related models $persons->getCollection()->each->load([ 'migration', 'naturalization', 'residence', 'family', 'internment' ]); return $persons; } /** * Get a specific migrant record by ID * * @param mixed $id * @return JsonResponse */ public function getRecord($id): JsonResponse { try { $person = Person::with([ 'migration', 'naturalization', 'residence', 'family', 'internment' ])->findOrFail($id); return response()->json([ 'success' => true, 'data' => $person, 'message' => 'Record retrieved successfully' ]); } catch (Exception $e) { return response()->json([ 'success' => false, 'message' => 'Record not found', 'error' => $e->getMessage() ], 404); } } }