Skip to content
Snippets Groups Projects
Commit d77d6ad7 authored by Sofiane Lasri's avatar Sofiane Lasri
Browse files

feat: add category localization support and CRUD operations

- Updated the database configuration to use in-memory SQLite for testing.
- Renamed `nameTranslation` to `nameTranslationKey` in `Category` model and updated the relation to `TranslationKey`.
- Added `CategoryController` methods: `store`, `edit`, and `update` for category management with localization support.
- Removed `CategoryRequest.php` and created `CategoryTest.php` for testing new features.
- Modified `edit.blade.php` to dynamically set titles and pre-fill form data for category editing.
- Updated `phpunit.xml` to use SQLite connection.
- Added relation `translations` and method `getTranslation` in `TranslationKey` model for fetching translations.
- New routes added for category creation, editing, and updating in `web.php`.
parent 866ce397
No related branches found
No related tags found
1 merge request!2feat(admin): ajouter gestion des catégories dans l'interface admin
Pipeline #595 passed
......@@ -22,7 +22,7 @@ LOG_LEVEL=debug
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
DB_DATABASE=:memory:
# DB_USERNAME=root
# DB_PASSWORD=
......
......@@ -3,6 +3,11 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Category;
use App\Models\Translation;
use App\Models\TranslationKey;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;
class CategoryController extends Controller
......@@ -30,7 +35,84 @@ public function index(): View
public function create(): View
{
return view('admin.categories.edit', [
'title' => 'Créer une catégorie',
'headerRoutes' => $this->headerRoutes,
]);
}
public function edit($id, Request $request): View
{
$request->validate([
'lang' => 'required|string|in:fr,en',
]);
$category = Category::findOrFail($id);
$name = $category->nameTranslationKey->getTranslation($request->input('lang'));
return view('admin.categories.edit', [
'title' => 'Modifier une catégorie',
'headerRoutes' => $this->headerRoutes,
'category' => $category,
'name' => $name,
'lang' => $request->input('lang'),
]);
}
public function store(Request $request)
{
$request->validate([
'lang' => 'required|string|in:fr,en',
'name' => 'required|string',
'slug' => 'required|string',
]);
$slug = Str::slug($request->input('slug'));
$translationKey = TranslationKey::create([
'key' => 'category_'.Str::uuid(),
]);
Translation::create([
'translation_key_id' => $translationKey->id,
'locale' => $request->input('lang'),
'text' => $request->input('name'),
]);
Category::create([
'slug' => $slug,
'name_translation_key_id' => $translationKey->id,
]);
return redirect()->route('admin.categories.index');
}
public function update(Request $request, int $id)
{
$request->validate([
'lang' => 'required|string|in:fr,en',
'name' => 'required|string',
'slug' => 'required|string',
]);
$slug = Str::slug($request->input('slug'));
$category = Category::findOrFail($id);
$translationKey = $category->nameTranslationKey;
Translation::updateOrCreate(
[
'translation_key_id' => $translationKey->id,
'locale' => $request->input('lang'),
],
[
'text' => $request->input('name'),
]
);
$category->update([
'slug' => $slug,
]);
return redirect()->route('admin.categories.index');
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CategoryRequest extends FormRequest
{
public function rules(): array
{
return [
'name_translation_key_id' => ['required', 'exists:translations'],
];
}
public function authorize(): bool
{
return true;
}
}
......@@ -17,8 +17,8 @@ class Category extends Model
'name_translation_key_id',
];
public function nameTranslation(): BelongsTo
public function nameTranslationKey(): BelongsTo
{
return $this->belongsTo(Translation::class, 'name_translation_key_id');
return $this->belongsTo(TranslationKey::class, 'name_translation_key_id');
}
}
......@@ -4,6 +4,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class TranslationKey extends Model
{
......@@ -14,4 +15,14 @@ class TranslationKey extends Model
protected $fillable = [
'key',
];
public function translations(): HasMany
{
return $this->hasMany(Translation::class);
}
public function getTranslation(string $locale): string
{
return $this->translations->firstWhere('locale', $locale)?->text ?? $this->key;
}
}
......@@ -22,8 +22,8 @@
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
......
@extends('layouts.admin', ['title' => 'Créer une catégorie', 'headerRoutes' => $headerRoutes]))
@extends('layouts.admin', ['title' => $title, 'headerRoutes' => $headerRoutes])
@section('content')
<h5>Information</h5>
......@@ -9,10 +9,14 @@
<div class="g-col-4">
<form action="" method="post">
@csrf
<x-bs.select label="Langue" name="lang" :options="['fr' => 'Français', 'en' => 'Anglais']" class="mb-3"/>
<x-bs.input label="Nom de la catégorie" name="name" class="mb-3"/>
<x-bs.input label="Slug" name="slug" class="mb-3"/>
<x-bs.button type="submit">Créer</x-bs.button>
@if(!empty($category))
<input hidden name="id" value="{{ $category->id }}"/>
@endif
<x-bs.select label="Langue" name="lang" :options="['fr' => 'Français', 'en' => 'Anglais']" class="mb-3"
selected="{{ $lang ?? 'fr' }}"/>
<x-bs.input label="Nom de la catégorie" name="name" class="mb-3" value="{{ $name ?? '' }}"/>
<x-bs.input label="Slug" name="slug" class="mb-3" value="{{ !empty($category) ? $category->slug : '' }}"/>
<x-bs.button type="submit">Enregister</x-bs.button>
</form>
</div>
</div>
......
@extends('layouts.admin', ['title' => 'Catégories', 'headerRoutes' => $headerRoutes]))
@extends('layouts.admin', ['title' => 'Catégories', 'headerRoutes' => $headerRoutes])
@section('content')
......
......@@ -20,4 +20,10 @@
->name('admin.categories.index');
Route::get('/categories/create', [CategoryController::class, 'create'])
->name('admin.categories.create');
Route::post('/categories', [CategoryController::class, 'store'])
->name('admin.categories.store');
Route::get('/categories/{category}/edit', [CategoryController::class, 'edit'])
->name('admin.categories.edit');
Route::put('/categories/{category}', [CategoryController::class, 'update'])
->name('admin.categories.update');
});
<?php
namespace Tests\Feature;
use App\Models\Category;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class CategoryTest extends TestCase
{
use RefreshDatabase, WithoutMiddleware;
#[Test]
public function it_can_create_a_category_with_valid_name()
{
$response = $this->post('/admin/categories', [
'name' => 'Nouvelle Catégorie',
'slug' => 'nouvelle-categorie',
'lang' => 'fr',
]);
$response->assertRedirect('/admin/categories');
$this->assertDatabaseHas('categories', [
'slug' => 'nouvelle-categorie',
]);
$this->assertDatabaseHas('translations', [
'text' => 'Nouvelle Catégorie',
'locale' => 'fr',
]);
}
#[Test]
public function it_fails_to_create_a_category_without_name()
{
$response = $this->post('/admin/categories', [
'slug' => 'nouvelle-categorie',
'lang' => 'fr',
]);
$response->assertSessionHasErrors('name');
}
#[Test]
public function it_can_update_a_category_with_valid_name()
{
$category = Category::factory()->create();
$response = $this->put("/admin/categories/{$category->id}", [
'name' => 'Catégorie Modifiée',
'slug' => 'categorie-modifiee',
'lang' => 'fr',
]);
$response->assertRedirect('/admin/categories');
$this->assertDatabaseHas('categories', [
'id' => $category->id,
'slug' => 'categorie-modifiee',
]);
$this->assertDatabaseHas('translations', [
'text' => 'Catégorie Modifiée',
'locale' => 'fr',
]);
}
#[Test]
public function it_fails_to_update_a_category_without_name()
{
$category = Category::factory()->create();
$response = $this->put("/admin/categories/{$category->id}", [
'slug' => 'categorie-modifiee',
'lang' => 'fr',
]);
$response->assertSessionHasErrors('name');
}
#[Test]
public function it_transforms_slug_correctly()
{
$response = $this->post('/admin/categories', [
'name' => 'Une Catégorie',
'slug' => 'Une Catégorie avec des Espaces!',
'lang' => 'fr',
]);
$response->assertRedirect('/admin/categories');
$this->assertDatabaseHas('categories', [
'slug' => 'une-categorie-avec-des-espaces',
]);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment