Merge branch 'features/typesense' into 'dev'

Features/typesense

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!8
This commit is contained in:
JOSSERAND GIOVANNI p2405212
2025-12-07 15:14:57 +00:00
7 changed files with 1248 additions and 484 deletions
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Typesense\Client;
use Exception;
use App\Models\Events;
class SearchController extends Controller
{
protected Client $client;
public function __construct()
{
$this->client = new Client([
'api_key' => '',
'nodes' => [
[
'host' => env('TYPESENSE_CONNECTION'),
'port' => '8108',
'protocol' => 'http',
],
],
]);
}
private function createEventsCollection()
{
try {
$collections = $this->client->collections->retrieve();
if (!in_array('events', array_column($collections, 'name'))) {
$this->client->collections->create([
'name' => 'events',
'fields' => [
['name' => 'name', 'type' => 'string'],
['name' => 'description', 'type' => 'string'],
],
]);
}
} catch (Exception $e) {
throw new Exception("Error while creating the events collection : " . $e->getMessage());
}
}
private function indexEvents()
{
try {
$events = Events::all();
foreach ($events as $event) {
$this->client->collections['events']->documents->upsert([
'id' => (string) $event->id,
'name' => $event->name,
'description' => $event->description,
]);
}
} catch (Exception $e) {
throw new Exception("Error while indexing events : " . $e->getMessage());
}
}
public function searchEvents(Request $request)
{
try {
$this->createEventsCollection();
$this->indexEvents();
$query = $request->input('query', '');
$searchResults = $this->client->collections['events']->documents->search([
'q' => $query,
'query_by' => 'name,description',
]);
return response()->json($searchResults);
} catch (Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
}
}
+2 -1
View File
@@ -12,7 +12,8 @@
"php": "^8.2", "php": "^8.2",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/sanctum": "^4.0", "laravel/sanctum": "^4.0",
"laravel/tinker": "^2.10.1" "laravel/tinker": "^2.10.1",
"typesense/typesense-php": "*"
}, },
"require-dev": { "require-dev": {
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
Generated
+1128 -481
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -36,8 +36,19 @@ services:
volumes: volumes:
- dbdata:/var/lib/mysql - dbdata:/var/lib/mysql
typesense:
image: typesense/typesense:29.0
restart: on-failure
ports:
- "8108:8108"
volumes:
- typesense-data:/data
command: '--data-dir /data --api-key= --enable-cors'
volumes: volumes:
dbdata: dbdata:
typesense-data:
networks: networks:
default: default:
+4 -1
View File
@@ -1,6 +1,7 @@
<?php <?php
use App\Http\Controllers\EventsController; use App\Http\Controllers\EventsController;
use App\Http\Controllers\SearchController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TasksController; use App\Http\Controllers\TasksController;
@@ -24,4 +25,6 @@ Route::middleware(['web', 'auth:sanctum'])->get('/events', [EventsController::cl
Route::middleware(['web', 'auth:sanctum'])->delete('/events/{id}', [EventsController::class, "delete"]); Route::middleware(['web', 'auth:sanctum'])->delete('/events/{id}', [EventsController::class, "delete"]);
Route::middleware(['web', 'auth:sanctum'])->get('/events/{id}', [EventsController::class, "getEvent"]); Route::middleware(['web', 'auth:sanctum'])->get('/events/search', [SearchController::class, "searchEvents"]);
Route::middleware(['web', 'auth:sanctum'])->get('/events/{id}', [EventsController::class, "getEvent"]);
+19
View File
@@ -0,0 +1,19 @@
meta {
name: Search events
type: http
seq: 7
}
get {
url: {{url}}/api/events/search?query=vile
body: none
auth: inherit
}
params:query {
query: vile
}
settings {
encodeUrl: true
}
+1 -1
View File
@@ -1,4 +1,4 @@
headers { headers {
Accept: application/json Accept: application/json
X-XSRF-TOKEN: X-XSRF-TOKEN: eyJpdiI6Ijl5dmtCZmFHRE90VVZBNTFoQ0xYMHc9PSIsInZhbHVlIjoibkR0OGM3bytFa0dUQWs3MGhPQzdwL3NzY2I2QnlrNVlVd3lxL2xuZ0NsK01tRFBFUGFFeWtRMHExSlNKLzBzUUt3NUYyMVNkY2NHc3lSbVVDc2kxdXNJbDJlYlZNTms5ZjBkVU5tYzI4ZmllK2g5ZTdGMldxK3p6Vjh5ZDBEcHAiLCJtYWMiOiI1MzA3MGViMzBjNmI5NTg5ZjhmZTI4ODU1MGZmMWQwYzg2NzU3N2RiNWRjMDdjODI3ODNkNzYzMmYyMDFkZTAxIiwidGFnIjoiIn0=
} }