migrants-nt-sec/app/Http/Controllers/PersonController.php

428 lines
16 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Http\Requests\StorePersonRequest;
use App\Http\Requests\UpdatePersonRequest;
use App\Http\Resources\PersonResource;
use App\Http\Resources\PersonCollection;
use App\Models\Person;
use App\Models\Migration;
use App\Models\Naturalization;
use App\Models\Residence;
use App\Models\Family;
use App\Models\Internment;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Builder;
use Carbon\Carbon;
use Exception;
class PersonController extends Controller
{
/**
* Public Search API - Search for persons without authentication.
* Allows filtering by multiple criteria.
*
* @param Request $request
* @return JsonResponse
*/
public function publicSearch(Request $request): JsonResponse
{
try {
// Start with the base query
$query = Person::query();
// Apply filters for Person fields
if ($request->has('firstName') && $request->firstName !== 'all') {
$query->where('christian_name', 'LIKE', "%{$request->firstName}%");
}
if ($request->has('lastName') && $request->lastName !== 'all') {
$query->where('surname', 'LIKE', "%{$request->lastName}%");
}
// Filter by region of origin (place_of_birth in Person table)
if ($request->has('regionOfOrigin') && $request->regionOfOrigin !== 'all') {
$query->where('place_of_birth', 'LIKE', "%{$request->regionOfOrigin}%");
}
// For filters that need to access related tables, use whereHas
// Filter by Year of Arrival (in Migration table)
if ($request->has('yearOfArrival') && $request->yearOfArrival !== 'all') {
$year = $request->yearOfArrival;
$query->whereHas('migration', function (Builder $query) use ($year) {
$query->whereYear('date_of_arrival_aus', $year)
->orWhereYear('date_of_arrival_nt', $year);
});
}
// Filter by Age at Migration (requires calculation)
if ($request->has('ageAtMigration') && $request->ageAtMigration !== 'all') {
$ageAtMigration = (int) $request->ageAtMigration;
$query->whereHas('migration', function (Builder $query) use ($ageAtMigration) {
$query->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 (in Residence table)
if ($request->has('settlementLocation') && $request->settlementLocation !== 'all') {
$location = $request->settlementLocation;
$query->whereHas('residence', function (Builder $query) use ($location) {
$query->where(function ($q) use ($location) {
$q->where('address', 'LIKE', "%{$location}%")
->orWhere('suburb', 'LIKE', "%{$location}%")
->orWhere('state', 'LIKE', "%{$location}%");
});
});
}
// Paginate the results (default 10 per page, can be customized with the 'per_page' parameter)
$perPage = $request->input('per_page', 10);
$persons = $query->paginate($perPage);
// Eager load related models for the collection
$persons->getCollection()->each->load([
'migration',
'naturalization',
'residence',
'family',
'internment'
]);
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);
}
}
/**
* Find a person by ID card number.
*
* @param string $idCardNo
* @return JsonResponse
*/
public function findByIdCard(string $idCardNo): JsonResponse
{
try {
$person = Person::with(['migration', 'naturalization', 'residence', 'family', 'internment'])
->where('id_card_no', $idCardNo)
->first();
if (!$person) {
return response()->json([
'success' => false,
'message' => 'Person not found with the provided ID card number'
], 404);
}
return response()->json([
'success' => true,
'data' => new PersonResource($person),
'message' => 'Person found by ID card number'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to retrieve person by ID card number',
'error' => $e->getMessage()
], 500);
}
}
/**
* Display a listing of the resource.
*
* @param Request $request
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
try {
$query = Person::query();
// Apply search filters if provided
if ($request->has('search')) {
$searchTerm = $request->search;
$query->where(function($q) use ($searchTerm) {
$q->where('full_name', 'LIKE', "%{$searchTerm}%")
->orWhere('surname', 'LIKE', "%{$searchTerm}%")
->orWhere('occupation', 'LIKE', "%{$searchTerm}%");
});
}
// Paginate results
$persons = $query->paginate(10);
// Eager load related models for each person in the collection
$persons->getCollection()->each->load([
'migration',
'naturalization',
'residence',
'family',
'internment'
]);
return response()->json([
'success' => true,
'data' => new PersonCollection($persons),
'message' => 'Persons retrieved successfully'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to retrieve persons',
'error' => $e->getMessage()
], 500);
}
}
/**
* Store a newly created resource in storage.
*
* @param StorePersonRequest $request
* @return JsonResponse
*/
public function store(StorePersonRequest $request): JsonResponse
{
try {
// Use DB transaction for atomic operations
$result = DB::transaction(function () use ($request) {
// Create person record
$person = Person::create($request->only([
'surname', 'christian_name', 'full_name', 'date_of_birth',
'place_of_birth', 'date_of_death', 'occupation',
'additional_notes', 'reference', 'id_card_no'
]));
// Create migration record if data is provided
if ($request->has('migration')) {
$person->migration()->create($request->migration);
}
// Create naturalization record if data is provided
if ($request->has('naturalization')) {
$person->naturalization()->create($request->naturalization);
}
// Create residence record if data is provided
if ($request->has('residence')) {
$person->residence()->create($request->residence);
}
// Create family record if data is provided
if ($request->has('family')) {
$person->family()->create($request->family);
}
// Create internment record if data is provided
if ($request->has('internment')) {
$person->internment()->create($request->internment);
}
// Load all relationships for the response
$person->load(['migration', 'naturalization', 'residence', 'family', 'internment']);
return $person;
});
return response()->json([
'success' => true,
'data' => new PersonResource($result),
'message' => 'Person created successfully'
], 201);
} catch (Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to create person',
'error' => $e->getMessage()
], 500);
}
}
/**
* Display the specified resource.
*
* @param string $id
* @return JsonResponse
*/
public function show(string $id): JsonResponse
{
try {
// Find person by ID and eager load all relationships
$person = Person::with(['migration', 'naturalization', 'residence', 'family', 'internment'])
->find($id);
if (!$person) {
return response()->json([
'success' => false,
'message' => 'Person not found'
], 404);
}
return response()->json([
'success' => true,
'data' => new PersonResource($person),
'message' => 'Person retrieved successfully'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to retrieve person',
'error' => $e->getMessage()
], 500);
}
}
/**
* Update the specified resource in storage.
*
* @param UpdatePersonRequest $request
* @param string $id
* @return JsonResponse
*/
public function update(UpdatePersonRequest $request, string $id): JsonResponse
{
try {
// Use DB transaction for atomic operations
$result = DB::transaction(function () use ($request, $id) {
// Find person by ID
$person = Person::findOrFail($id);
// Update person record
$person->update($request->only([
'surname', 'christian_name', 'full_name', 'date_of_birth',
'place_of_birth', 'date_of_death', 'occupation',
'additional_notes', 'reference', 'id_card_no'
]));
// Update migration record if data is provided
if ($request->has('migration')) {
if ($person->migration) {
$person->migration->update($request->migration);
} else {
$person->migration()->create($request->migration);
}
}
// Update naturalization record if data is provided
if ($request->has('naturalization')) {
if ($person->naturalization) {
$person->naturalization->update($request->naturalization);
} else {
$person->naturalization()->create($request->naturalization);
}
}
// Update residence record if data is provided
if ($request->has('residence')) {
if ($person->residence) {
$person->residence->update($request->residence);
} else {
$person->residence()->create($request->residence);
}
}
// Update family record if data is provided
if ($request->has('family')) {
if ($person->family) {
$person->family->update($request->family);
} else {
$person->family()->create($request->family);
}
}
// Update internment record if data is provided
if ($request->has('internment')) {
if ($person->internment) {
$person->internment->update($request->internment);
} else {
$person->internment()->create($request->internment);
}
}
// Load all relationships for the response
$person->load(['migration', 'naturalization', 'residence', 'family', 'internment']);
return $person;
});
return response()->json([
'success' => true,
'data' => new PersonResource($result),
'message' => 'Person updated successfully'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to update person',
'error' => $e->getMessage()
], 500);
}
}
/**
* Remove the specified resource from storage.
*
* @param string $id
* @return JsonResponse
*/
public function destroy(string $id): JsonResponse
{
try {
// Use DB transaction for atomic operations
DB::transaction(function () use ($id) {
// Find person by ID with related models
$person = Person::with([
'migration', 'naturalization', 'residence', 'family', 'internment'
])->findOrFail($id);
// Manually delete each related model to ensure soft deletes work correctly
if ($person->migration) {
$person->migration->delete();
}
if ($person->naturalization) {
$person->naturalization->delete();
}
if ($person->residence) {
$person->residence->delete();
}
if ($person->family) {
$person->family->delete();
}
if ($person->internment) {
$person->internment->delete();
}
// Now delete the person record
$person->delete();
});
return response()->json([
'success' => true,
'message' => 'Person deleted successfully'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to delete person',
'error' => $e->getMessage()
], 500);
}
}
}