From ae522c5640150f0f4c2a59824e997fd2a1693a70 Mon Sep 17 00:00:00 2001 From: soheil khaledabadi Date: Fri, 8 May 2026 18:15:21 +0330 Subject: [PATCH] feat: add legal opinions admin management --- .../Admin/LegalOpinionCategoryController.php | 69 ++++++++++ .../Admin/LegalOpinionController.php | 126 ++++++++++++++++++ app/Models/Art.php | 5 + app/Models/LegalOpinion.php | 32 +++++ app/Models/LegalOpinionCategory.php | 18 +++ ..._create_legal_opinion_categories_table.php | 28 ++++ ..._08_000002_create_legal_opinions_table.php | 35 +++++ ..._000003_create_art_legal_opinion_table.php | 31 +++++ .../legal-opinion-category/create.blade.php | 25 ++++ .../legal-opinion-category/index.blade.php | 44 ++++++ .../legal-opinion-category/update.blade.php | 26 ++++ .../admin/legal-opinion/create.blade.php | 65 +++++++++ .../views/admin/legal-opinion/index.blade.php | 52 ++++++++ .../admin/legal-opinion/update.blade.php | 66 +++++++++ resources/views/admin/partial/menu.blade.php | 22 +++ routes/web.php | 6 +- 16 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/Admin/LegalOpinionCategoryController.php create mode 100644 app/Http/Controllers/Admin/LegalOpinionController.php create mode 100644 app/Models/LegalOpinion.php create mode 100644 app/Models/LegalOpinionCategory.php create mode 100644 database/migrations/2026_05_08_000001_create_legal_opinion_categories_table.php create mode 100644 database/migrations/2026_05_08_000002_create_legal_opinions_table.php create mode 100644 database/migrations/2026_05_08_000003_create_art_legal_opinion_table.php create mode 100644 resources/views/admin/legal-opinion-category/create.blade.php create mode 100644 resources/views/admin/legal-opinion-category/index.blade.php create mode 100644 resources/views/admin/legal-opinion-category/update.blade.php create mode 100644 resources/views/admin/legal-opinion/create.blade.php create mode 100644 resources/views/admin/legal-opinion/index.blade.php create mode 100644 resources/views/admin/legal-opinion/update.blade.php diff --git a/app/Http/Controllers/Admin/LegalOpinionCategoryController.php b/app/Http/Controllers/Admin/LegalOpinionCategoryController.php new file mode 100644 index 0000000..b0941f1 --- /dev/null +++ b/app/Http/Controllers/Admin/LegalOpinionCategoryController.php @@ -0,0 +1,69 @@ +filled('q')) { + $q = $request->q; + $query->where('name', 'like', "%{$q}%"); + } + + $perPage = min(max((int) $request->input('per_page', 15), 10), 100); + $categories = $query->paginate($perPage)->withQueryString(); + + return view('admin.legal-opinion-category.index', compact('categories')); + } + + public function create() + { + return view('admin.legal-opinion-category.create'); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'name' => 'required|string|unique:legal_opinion_categories,name', + ]); + + LegalOpinionCategory::create($validated); + + return redirect(route('legal-opinion-category.index')); + } + + public function edit(LegalOpinionCategory $legalOpinionCategory) + { + return view('admin.legal-opinion-category.update', compact('legalOpinionCategory')); + } + + public function show(LegalOpinionCategory $legalOpinionCategory) + { + return redirect(route('legal-opinion-category.edit', $legalOpinionCategory->id)); + } + + public function update(Request $request, LegalOpinionCategory $legalOpinionCategory) + { + $validated = $request->validate([ + 'name' => 'required|string|unique:legal_opinion_categories,name,' . $legalOpinionCategory->id, + ]); + + $legalOpinionCategory->update($validated); + + return redirect(route('legal-opinion-category.edit', $legalOpinionCategory->id)); + } + + public function destroy(LegalOpinionCategory $legalOpinionCategory) + { + $legalOpinionCategory->delete(); + + return redirect(route('legal-opinion-category.index')); + } +} diff --git a/app/Http/Controllers/Admin/LegalOpinionController.php b/app/Http/Controllers/Admin/LegalOpinionController.php new file mode 100644 index 0000000..efa9b46 --- /dev/null +++ b/app/Http/Controllers/Admin/LegalOpinionController.php @@ -0,0 +1,126 @@ +filled('q')) { + $q = $request->q; + $query->where(function ($qry) use ($q) { + $qry->where('opinion_number', 'like', "%{$q}%") + ->orWhere('subject', 'like', "%{$q}%") + ->orWhere('full_text', 'like', "%{$q}%") + ->orWhere('issuing_authority', 'like', "%{$q}%"); + }); + } + + $perPage = min(max((int) $request->input('per_page', 15), 10), 100); + $legalOpinions = $query->latest()->paginate($perPage)->withQueryString(); + + return view('admin.legal-opinion.index', compact('legalOpinions')); + } + + public function create() + { + $arts = Art::all(); + $categories = LegalOpinionCategory::all(); + + return view('admin.legal-opinion.create', compact('arts', 'categories')); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'opinion_number' => [ + 'required', + Rule::unique('legal_opinions', 'opinion_number')->where('category_id', $request->input('category_id')), + ], + 'opinion_date' => 'nullable|date', + 'subject' => 'nullable|string|max:1000', + 'full_text' => 'required|string', + 'issuing_authority' => 'nullable|string', + 'category_id' => 'required|exists:legal_opinion_categories,id', + 'art_ids' => 'nullable|array', + 'art_ids.*' => 'exists:art,id', + ]); + + $legalOpinion = LegalOpinion::create([ + 'opinion_number' => $validated['opinion_number'], + 'opinion_date' => $validated['opinion_date'] ?? null, + 'subject' => $validated['subject'] ?? null, + 'full_text' => $validated['full_text'], + 'issuing_authority' => $validated['issuing_authority'] ?? null, + 'category_id' => $validated['category_id'], + ]); + + if (!empty($validated['art_ids'])) { + $legalOpinion->arts()->attach($validated['art_ids']); + } + + return redirect(route('legal-opinion.index')); + } + + public function edit(LegalOpinion $legalOpinion) + { + $arts = Art::all(); + $categories = LegalOpinionCategory::all(); + $selectedArtIds = $legalOpinion->arts->pluck('id')->toArray(); + + return view('admin.legal-opinion.update', compact('legalOpinion', 'arts', 'categories', 'selectedArtIds')); + } + + public function show(LegalOpinion $legalOpinion) + { + return redirect(route('legal-opinion.edit', $legalOpinion->id)); + } + + public function update(Request $request, LegalOpinion $legalOpinion) + { + $validated = $request->validate([ + 'opinion_number' => [ + 'required', + Rule::unique('legal_opinions', 'opinion_number') + ->where('category_id', $request->input('category_id')) + ->ignore($legalOpinion->id), + ], + 'opinion_date' => 'nullable|date', + 'subject' => 'nullable|string|max:1000', + 'full_text' => 'required|string', + 'issuing_authority' => 'nullable|string', + 'category_id' => 'required|exists:legal_opinion_categories,id', + 'art_ids' => 'nullable|array', + 'art_ids.*' => 'exists:art,id', + ]); + + $legalOpinion->update([ + 'opinion_number' => $validated['opinion_number'], + 'opinion_date' => $validated['opinion_date'] ?? null, + 'subject' => $validated['subject'] ?? null, + 'full_text' => $validated['full_text'], + 'issuing_authority' => $validated['issuing_authority'] ?? null, + 'category_id' => $validated['category_id'], + ]); + + $legalOpinion->arts()->sync($validated['art_ids'] ?? []); + + return redirect(route('legal-opinion.edit', $legalOpinion->id)); + } + + public function destroy(LegalOpinion $legalOpinion) + { + $legalOpinion->delete(); + + return redirect(route('legal-opinion.index')); + } +} diff --git a/app/Models/Art.php b/app/Models/Art.php index 350f7e3..44d4e28 100644 --- a/app/Models/Art.php +++ b/app/Models/Art.php @@ -53,6 +53,11 @@ class Art extends Model return $this->belongsToMany(JudicialPrecedent::class, 'art_judicial_precedent'); } + public function legalOpinions() + { + return $this->belongsToMany(LegalOpinion::class, 'art_legal_opinion'); + } + public static function search($searchTerm) { return self::where('title', 'LIKE', "%{$searchTerm}%") diff --git a/app/Models/LegalOpinion.php b/app/Models/LegalOpinion.php new file mode 100644 index 0000000..4422f24 --- /dev/null +++ b/app/Models/LegalOpinion.php @@ -0,0 +1,32 @@ +belongsToMany(Art::class, 'art_legal_opinion'); + } + + public function category() + { + return $this->belongsTo(LegalOpinionCategory::class, 'category_id'); + } +} diff --git a/app/Models/LegalOpinionCategory.php b/app/Models/LegalOpinionCategory.php new file mode 100644 index 0000000..bff3d06 --- /dev/null +++ b/app/Models/LegalOpinionCategory.php @@ -0,0 +1,18 @@ +hasMany(LegalOpinion::class, 'category_id'); + } +} diff --git a/database/migrations/2026_05_08_000001_create_legal_opinion_categories_table.php b/database/migrations/2026_05_08_000001_create_legal_opinion_categories_table.php new file mode 100644 index 0000000..bb6463f --- /dev/null +++ b/database/migrations/2026_05_08_000001_create_legal_opinion_categories_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name')->unique()->comment('نام دسته‌بندی'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('legal_opinion_categories'); + } +}; diff --git a/database/migrations/2026_05_08_000002_create_legal_opinions_table.php b/database/migrations/2026_05_08_000002_create_legal_opinions_table.php new file mode 100644 index 0000000..1d76b47 --- /dev/null +++ b/database/migrations/2026_05_08_000002_create_legal_opinions_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('opinion_number')->comment('شماره نظریه'); + $table->date('opinion_date')->nullable()->comment('تاریخ نظریه'); + $table->string('subject', 1000)->nullable()->comment('موضوع استعلام یا نظریه'); + $table->longText('full_text')->comment('متن کامل نظریه و استعلام'); + $table->string('issuing_authority')->nullable()->comment('مرجع صدور'); + $table->foreignId('category_id')->constrained('legal_opinion_categories')->onDelete('cascade')->comment('شناسه دسته‌بندی'); + $table->timestamps(); + + $table->unique(['opinion_number', 'category_id'], 'unique_opinion_category'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('legal_opinions'); + } +}; diff --git a/database/migrations/2026_05_08_000003_create_art_legal_opinion_table.php b/database/migrations/2026_05_08_000003_create_art_legal_opinion_table.php new file mode 100644 index 0000000..3655369 --- /dev/null +++ b/database/migrations/2026_05_08_000003_create_art_legal_opinion_table.php @@ -0,0 +1,31 @@ +id(); + $table->foreignId('art_id')->constrained('art')->onDelete('cascade'); + $table->foreignId('legal_opinion_id')->constrained('legal_opinions')->onDelete('cascade'); + $table->timestamps(); + + $table->unique(['art_id', 'legal_opinion_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('art_legal_opinion'); + } +}; diff --git a/resources/views/admin/legal-opinion-category/create.blade.php b/resources/views/admin/legal-opinion-category/create.blade.php new file mode 100644 index 0000000..38b7b85 --- /dev/null +++ b/resources/views/admin/legal-opinion-category/create.blade.php @@ -0,0 +1,25 @@ +@extends('admin.layouts.app') +@section('content') +
+ @include('admin.layouts.errors') +
+
+
+

افزودن دسته‌بندی نظریه حقوقی

+
+
+ @csrf +
+ + +
+ + + بازگشت +
+
+
+
+
+
+@endsection diff --git a/resources/views/admin/legal-opinion-category/index.blade.php b/resources/views/admin/legal-opinion-category/index.blade.php new file mode 100644 index 0000000..74bce5a --- /dev/null +++ b/resources/views/admin/legal-opinion-category/index.blade.php @@ -0,0 +1,44 @@ +@extends('admin.layouts.app') +@section('content') +
+
+
+
+ @include('admin.partial.list-filter', ['filterRoute' => 'legal-opinion-category.index']) + +
+
+
+
+@endsection diff --git a/resources/views/admin/legal-opinion-category/update.blade.php b/resources/views/admin/legal-opinion-category/update.blade.php new file mode 100644 index 0000000..1d9f1b7 --- /dev/null +++ b/resources/views/admin/legal-opinion-category/update.blade.php @@ -0,0 +1,26 @@ +@extends('admin.layouts.app') +@section('content') +
+ @include('admin.layouts.errors') +
+
+
+

ویرایش دسته‌بندی نظریه حقوقی

+
+
+ @csrf + @method('PUT') +
+ + +
+ + + بازگشت +
+
+
+
+
+
+@endsection diff --git a/resources/views/admin/legal-opinion/create.blade.php b/resources/views/admin/legal-opinion/create.blade.php new file mode 100644 index 0000000..7ad9f81 --- /dev/null +++ b/resources/views/admin/legal-opinion/create.blade.php @@ -0,0 +1,65 @@ +@extends('admin.layouts.app') +@section('content') +
+ @include('admin.layouts.errors') +
+
+
+

افزودن نظریه حقوقی

+
+
+ @csrf +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + برای انتخاب چند ماده، کلید Ctrl (یا Cmd در Mac) را نگه دارید +
+ + + بازگشت +
+
+
+
+
+
+@endsection diff --git a/resources/views/admin/legal-opinion/index.blade.php b/resources/views/admin/legal-opinion/index.blade.php new file mode 100644 index 0000000..0d3ca1c --- /dev/null +++ b/resources/views/admin/legal-opinion/index.blade.php @@ -0,0 +1,52 @@ +@extends('admin.layouts.app') +@section('content') +
+
+
+
+ @include('admin.partial.list-filter', ['filterRoute' => 'legal-opinion.index']) + +
+
+
+
+@endsection diff --git a/resources/views/admin/legal-opinion/update.blade.php b/resources/views/admin/legal-opinion/update.blade.php new file mode 100644 index 0000000..a987d17 --- /dev/null +++ b/resources/views/admin/legal-opinion/update.blade.php @@ -0,0 +1,66 @@ +@extends('admin.layouts.app') +@section('content') +
+ @include('admin.layouts.errors') +
+
+
+

ویرایش نظریه حقوقی

+
+
+ @csrf + @method('PUT') +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + برای انتخاب چند ماده، کلید Ctrl (یا Cmd در Mac) را نگه دارید +
+ + + بازگشت +
+
+
+
+
+
+@endsection diff --git a/resources/views/admin/partial/menu.blade.php b/resources/views/admin/partial/menu.blade.php index e5085ff..046cb6b 100644 --- a/resources/views/admin/partial/menu.blade.php +++ b/resources/views/admin/partial/menu.blade.php @@ -220,6 +220,28 @@ +
  • + + + نظریه‌های حقوقی + + +
  • + +
  • + + + دسته‌بندی نظریه‌ها + + +
  • +
  • diff --git a/routes/web.php b/routes/web.php index d5cff14..b305a2a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -9,8 +9,11 @@ use App\Http\Controllers\Admin\ChapterController; use App\Http\Controllers\Admin\DivisionController; use App\Http\Controllers\Admin\GateController; use App\Http\Controllers\Admin\HomeController; +use App\Http\Controllers\Admin\JudicialPrecedentController; use App\Http\Controllers\Admin\JudicialPrecedentCategoryController; use App\Http\Controllers\Admin\LawController; +use App\Http\Controllers\Admin\LegalOpinionController; +use App\Http\Controllers\Admin\LegalOpinionCategoryController; use App\Http\Controllers\Admin\NotificationController; use App\Http\Controllers\Admin\PartController; use App\Http\Controllers\Admin\SectionController; @@ -42,6 +45,7 @@ Route::middleware(['auth',config('jetstream.auth_session')])->group(function () Route::resource('notifications', NotificationController::class); Route::resource('judicial-precedent', JudicialPrecedentController::class); Route::resource('judicial-precedent-category', JudicialPrecedentCategoryController::class); + Route::resource('legal-opinion', LegalOpinionController::class); + Route::resource('legal-opinion-category', LegalOpinionCategoryController::class); Route::get('suggestions',[SuggestionController::class,'index'])->name('suggestions.index'); }); -