291 lines
8.8 KiB
PHP
291 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Http\Resources\PersonCollection;
|
|
use App\Models\Person;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Exception;
|
|
|
|
class PublicSearchController extends Controller
|
|
{
|
|
/**
|
|
* Search for persons with various filters
|
|
*
|
|
* @param Request $request
|
|
* @return JsonResponse
|
|
*/
|
|
public function search(Request $request): JsonResponse
|
|
{
|
|
try {
|
|
$query = $this->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);
|
|
}
|
|
}
|
|
}
|