1.2: restructure controllers to Api/ prefix and update routes

This commit is contained in:
parsa aghaei 2026-06-23 18:09:15 +03:30
parent cbcccfcbf8
commit 28c7a317e5
11 changed files with 137 additions and 271 deletions

View File

@ -0,0 +1,109 @@
<?php
namespace App\Http\Controllers\Api\Blog;
use App\Http\Controllers\Controller;
use App\Http\Requests\Blog\StoreCategoryRequest;
use App\Http\Requests\Blog\UpdateCategoryRequest;
use App\Http\Resources\CategoryResource;
use App\Http\Resources\PostResource;
use App\Models\Blog\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
public function index(Request $request)
{
$filter = $request->input('filter');
$sortBy = $request->input('sort_by', 'created_at');
$sortDirection = $request->input('sort_direction', 'desc');
$perPage = $request->input('per_page', 10);
$query = Category::with('posts');
if (!empty($filter)) {
$query->where('name', 'like', '%' . $filter . '%');
}
$query->orderBy($sortBy, $sortDirection);
$categories = $query->paginate($perPage);
return CategoryResource::collection($categories);
}
public function show($id)
{
$category = Category::with('posts')->findOrFail($id);
return new CategoryResource($category);
}
public function getCategoryWithPosts(Request $request, $slug)
{
$category = Category::where('slug', $slug)->first();
if (!$category) {
return response()->json([
'message' => 'Category not found.'
], 404);
}
$perPage = $request->input('per_page', 10);
$filter = $request->input('filter');
$sortBy = $request->input('sort_by', 'published_at');
$sortDirection = $request->input('sort_direction', 'desc');
$postsQuery = $category->posts()->with(['category', 'tags', 'author']);
if (!empty($filter)) {
$postsQuery->where('title', 'like', '%' . $filter . '%');
}
$postsQuery->orderBy($sortBy, $sortDirection);
$posts = $postsQuery->paginate($perPage);
$meta = [
'total' => $posts->total(),
'per_page' => $posts->perPage(),
'current_page' => $posts->currentPage(),
'last_page' => $posts->lastPage(),
'from' => $posts->firstItem(),
'to' => $posts->lastItem(),
];
$links = [
'first' => $posts->url(1),
'last' => $posts->url($posts->lastPage()),
'prev' => $posts->previousPageUrl(),
'next' => $posts->nextPageUrl(),
];
return response()->json([
'category' => new CategoryResource($category),
'posts' => PostResource::collection($posts),
'meta' => $meta,
'links' => $links,
], 200);
}
public function store(StoreCategoryRequest $request)
{
$category = Category::create($request->validated());
return new CategoryResource($category);
}
public function update(UpdateCategoryRequest $request, $id)
{
$category = Category::findOrFail($id);
$category->update($request->validated());
return new CategoryResource($category);
}
public function destroy($id)
{
$category = Category::findOrFail($id);
$category->delete();
return response()->json(['message' => 'Category deleted successfully'], 200);
}
}

View File

@ -1,47 +1,36 @@
<?php
namespace App\Http\Controllers\Blog;
namespace App\Http\Controllers\Api\Blog;
use App\Http\Controllers\Controller;
use App\Http\Resources\CategoryResource;
use App\Http\Resources\PostResource;
use App\Models\Blog\Category;
use App\Models\Blog\Post;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* برگرداندن داده‌های مورد نیاز برای صفحه‌ی اصلی
*
* @return \Illuminate\Http\JsonResponse
*/
public function index()
{
// 1. 5 پست آخر
$latestPosts = Post::with(['category', 'tags', 'author'])
->orderBy('published_at', 'desc')
->take(5)
->get();
// 2. 5 دسته‌بندی آخر
$latestCategories = Category::orderBy('created_at', 'desc')
->take(5)
->get();
// 3. 5 پست با بیشترین بازدید
$mostViewedPosts = Post::with(['category', 'tags', 'author'])
->orderBy('views', 'desc')
->take(5)
->get();
// 4. 4 پست تصادفی
$randomPosts = Post::with(['category', 'tags', 'author'])
->inRandomOrder()
->take(4)
->get();
// بازگشت به صورت JSON با استفاده از منابع (Resources)
return response()->json([
'latest_posts' => PostResource::collection($latestPosts),
'latest_categories' => CategoryResource::collection($latestCategories),

View File

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Blog;
namespace App\Http\Controllers\Api\Blog;
use App\Http\Controllers\Controller;
use App\Http\Requests\Blog\StorePostRequest;
@ -11,47 +11,36 @@
class PostController extends Controller
{
// نمایش لیست پست‌ها با فیلتر و صفحه‌بندی
public function index(Request $request)
{
// دریافت پارامترهای فیلتر از درخواست
$filters = $request->only(['category', 'tag', 'search', 'author', 'published']);
// دریافت پارامترهای مرتب‌سازی از درخواست
$sortField = $request->get('sort_field', 'published_at'); // فیلد پیش‌فرض: published_at
$sortDirection = $request->get('sort_direction', 'desc'); // جهت پیش‌فرض: نزولی
$sortField = $request->get('sort_field', 'published_at');
$sortDirection = $request->get('sort_direction', 'desc');
// دریافت پارامترهای صفحه‌بندی از درخواست
$perPage = $request->get('per_page', 10); // تعداد آیتم‌ها در هر صفحه (پیش‌فرض: ۱۰)
$perPage = $request->get('per_page', 10);
// ساخت Query با اعمال فیلترها و مرتب‌سازی
$query = Post::with(['category', 'tags', 'author'])
->filter($filters)
->sort($sortField, $sortDirection);
// اعمال صفحه‌بندی
$posts = $query->paginate($perPage);
// بازگشت نتایج به صورت JSON با استفاده از Resource
return PostResource::collection($posts);
}
// نمایش یک پست خاص
public function show($slug)
{
// یافتن پست بر اساس slug و بارگذاری روابط مرتبط
$post = Post::with(['category', 'tags', 'author', 'relatedPosts.category', 'relatedPosts.tags', 'relatedPosts.author'])
->where('slug', $slug)
->firstOrFail(); // در صورت عدم وجود پست، خطای 404 برمی‌گرداند
->firstOrFail();
// بازگشت پست و پست‌های مرتبط به صورت JSON با استفاده از منابع
return response()->json([
'post' => new PostResource($post),
'related_posts' => PostResource::collection($post->relatedPosts->sortByDesc('published_at')->take(5)), // بازگشت ۵ پست مرتبط جدیدترین
'related_posts' => PostResource::collection($post->relatedPosts->sortByDesc('published_at')->take(5)),
], 200);
}
// ذخیره یک پست جدید
public function store(StorePostRequest $request)
{
$post = Post::create($request->validated());
@ -63,7 +52,6 @@ public function store(StorePostRequest $request)
return new PostResource($post->load(['category', 'tags', 'author']));
}
// به‌روزرسانی یک پست خاص
public function update(UpdatePostRequest $request, $id)
{
$post = Post::findOrFail($id);
@ -76,7 +64,6 @@ public function update(UpdatePostRequest $request, $id)
return new PostResource($post->load(['category', 'tags', 'author']));
}
// حذف یک پست خاص
public function destroy($id)
{
$post = Post::findOrFail($id);

View File

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Blog;
namespace App\Http\Controllers\Api\Blog;
use App\Http\Controllers\Controller;
use App\Http\Requests\Blog\StoreTagRequest;
@ -11,44 +11,36 @@
class TagController extends Controller
{
// نمایش لیست تگ‌ها با صفحه‌بندی
public function index(Request $request)
{
$tags = Tag::with('posts')->paginate(10);
return TagResource::collection($tags);
}
// نمایش یک تگ خاص
public function show($id)
{
$tag = Tag::with('posts')->findOrFail($id);
return new TagResource($tag);
}
// ذخیره یک تگ جدید
public function store(StoreTagRequest $request)
{
$tag = Tag::create($request->validated());
return new TagResource($tag);
}
// به‌روزرسانی یک تگ خاص
public function update(UpdateTagRequest $request, $id)
{
$tag = Tag::findOrFail($id);
$tag->update($request->validated());
return new TagResource($tag);
}
// حذف یک تگ خاص
public function destroy($id)
{
$tag = Tag::findOrFail($id);
$tag->posts()->detach();
$tag->delete();
return response()->json(['message' => 'Tag deleted successfully'], 200);
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\Website;
namespace App\Http\Controllers\Api\Website;
use App\Http\Controllers\Controller;
use App\Http\Requests\Website\StoreAboutMeRequest;
@ -11,7 +11,7 @@ class AboutMeController extends Controller
{
public function index()
{
$aboutMe = AboutMe::with('skills.translations')->first(); // بارگذاری مهارت‌ها و ترجمه‌ها
$aboutMe = AboutMe::with('skills.translations')->first();
return response()->json($aboutMe);
}
@ -40,33 +40,29 @@ public function destroy($id)
return response()->json(null, 204);
}
// متد جدید برای دریافت ترجمه بر اساس locale از کوکی
public function getTranslation($id, $locale)
{
// بارگذاری AboutMe با ترجمه‌های مربوط به locale و مهارت‌ها
$aboutMe = AboutMe::with(['translations' => function ($query) use ($locale) {
$query->where('locale', $locale);
}, 'skills.translations' => function ($query) use ($locale) {
$query->where('locale', $locale);
}])->findOrFail($id);
// اگر ترجمه موجود نیست، می‌توانید ترجمه پیش‌فرض یا خطا را برگردانید
if ($aboutMe->translations->isEmpty()) {
return response()->json(['message' => 'Translation not found', 'locale' => $locale], 404);
}
// ترکیب اطلاعات AboutMe و ترجمه
$translation = $aboutMe->translations->first(); // فقط یک ترجمه دریافت می‌کنیم
$translation = $aboutMe->translations->first();
$skills = $aboutMe->skills->map(function ($skill) use ($locale) {
$translation = $skill->getTranslation($locale); // گرفتن ترجمه برای هر مهارت
$translation = $skill->getTranslation($locale);
return [
'id' => $skill->id,
'title' => $translation ? $translation->title : null, // عنوان از ترجمه
'description' => $translation ? $translation->description : null, // توضیحات از ترجمه
'image' => $skill->image, // تصویر
'link' => $skill->link, // لینک
'percentage' => $skill->percentage, // درصد
'title' => $translation ? $translation->title : null,
'description' => $translation ? $translation->description : null,
'image' => $skill->image,
'link' => $skill->link,
'percentage' => $skill->percentage,
];
});
@ -75,7 +71,7 @@ public function getTranslation($id, $locale)
'title' => $translation->title,
'description' => $translation->description,
'image' => $aboutMe->image,
'skills' => $skills, // مهارت‌ها اکنون بارگذاری شده‌اند
'skills' => $skills,
];
return response()->json($data);

View File

@ -1,6 +1,6 @@
<?php
namespace App\Http\Controllers\website;
namespace App\Http\Controllers\Api\Website;
use App\Http\Controllers\Controller;
use App\Http\Requests\Website\StoreProjectRequest;
@ -12,10 +12,8 @@ class ProjectController extends Controller
{
public function index($locale): \Illuminate\Http\JsonResponse
{
// Read per_page from query string or set a default value
$perPage = request()->query('per_page', 10); // مقدار پیش‌فرض ۱۰ در نظر گرفته می‌شود
$perPage = request()->query('per_page', 10);
// Retrieve projects with translations and categories
$projects = Project::with('translations', 'category.translations')->paginate($perPage);
$formattedProjects = $projects->items();
@ -53,12 +51,10 @@ public function index($locale): \Illuminate\Http\JsonResponse
]);
}
public function store(StoreProjectRequest $request)
{
$project = Project::create($request->only(['category_id', 'image1', 'image2']));
// ایجاد ترجمه‌ها
foreach (['fa', 'en'] as $locale) {
$project->translations()->create([
'locale' => $locale,
@ -92,13 +88,11 @@ public function show($id)
return response()->json(['project' => $formattedProject]);
}
public function update(UpdateProjectRequest $request, $id)
{
$project = Project::findOrFail($id);
$project->update($request->only(['category_id', 'image1', 'image2']));
// به‌روزرسانی ترجمه‌ها
foreach (['fa', 'en'] as $locale) {
$project->translations()->updateOrCreate(
['locale' => $locale],

View File

@ -1,23 +1,18 @@
<?php
namespace App\Http\Controllers\Website;
namespace App\Http\Controllers\Api\Website;
use App\Http\Controllers\Controller;
use App\Models\Website\Service;
class ServiceController extends Controller
{
/**
* دریافت لیست خدمات با ترجمه‌ها بر اساس زبان
*/
public function index($locale)
{
// گرفتن همه خدمات به همراه ترجمه‌ها
$services = Service::with(['translations' => function ($query) use ($locale) {
$query->where('locale', $locale);
}])->get();
// فرمتی که می‌خواهیم به کاربر ارسال کنیم
$response = $services->map(function ($service) use ($locale) {
return [
'id' => $service->id,
@ -33,9 +28,6 @@ public function index($locale)
return response()->json($response);
}
/**
* نمایش یک خدمت خاص با ترجمه
*/
public function showTranslation($id, $locale)
{
$service = Service::with('translations')->findOrFail($id);

View File

@ -1,144 +0,0 @@
<?php
namespace App\Http\Controllers\Blog;
use App\Http\Controllers\Controller;
use App\Http\Requests\Blog\StoreCategoryRequest;
use App\Http\Requests\Blog\UpdateCategoryRequest;
use App\Http\Resources\CategoryResource;
use App\Http\Resources\PostResource;
use App\Models\Blog\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
// نمایش لیست دسته‌بندی‌ها با صفحه‌بندی
public function index(Request $request)
{
// گرفتن فیلتر و سورت از درخواست کاربر
$filter = $request->input('filter'); // فیلتر (به عنوان مثال، نام دسته‌بندی)
$sortBy = $request->input('sort_by', 'created_at'); // مرتب‌سازی (پیش‌فرض بر اساس زمان ایجاد)
$sortDirection = $request->input('sort_direction', 'desc'); // جهت مرتب‌سازی (پیش‌فرض نزولی)
$perPage = $request->input('per_page', 10); // تعداد آیتم‌ها در هر صفحه (پیش‌فرض ۱۰)
// شروع کوئری با مدل دسته‌بندی و روابط
$query = Category::with('posts');
// اعمال فیلتر در صورت موجود بودن
if (!empty($filter)) {
$query->where('name', 'like', '%' . $filter . '%');
}
// اعمال مرتب‌سازی
$query->orderBy($sortBy, $sortDirection);
// گرفتن نتایج با پجینیشن
$categories = $query->paginate($perPage);
// بازگشت داده‌ها با استفاده از ریسورس
return CategoryResource::collection($categories);
}
// نمایش یک دسته‌بندی خاص
public function show($id)
{
$category = Category::with('posts')->findOrFail($id);
return new CategoryResource($category);
}
/**
* نمایش دسته‌بندی و پست‌های مرتبط با آن بر اساس slug
*
* @param \Illuminate\Http\Request $request
* @param string $slug
* @return \Illuminate\Http\JsonResponse
*/
public function getCategoryWithPosts(Request $request, $slug)
{
// یافتن دسته‌بندی بر اساس slug
$category = Category::where('slug', $slug)->first();
if (!$category) {
return response()->json([
'message' => 'دسته‌بندی مورد نظر یافت نشد.'
], 404);
}
// دریافت تعداد پست‌ها در هر صفحه (پیش‌فرض: ۱۰)
$perPage = $request->input('per_page', 10);
// دریافت فیلتر و سورت از درخواست
$filter = $request->input('filter'); // فیلتر (به عنوان مثال، عنوان پست)
$sortBy = $request->input('sort_by', 'published_at'); // مرتب‌سازی (پیش‌فرض بر اساس تاریخ انتشار)
$sortDirection = $request->input('sort_direction', 'desc'); // جهت مرتب‌سازی (پیش‌فرض نزولی)
// شروع کوئری با پست‌های مربوط به دسته‌بندی
$postsQuery = $category->posts()->with(['category', 'tags', 'author']);
// اعمال فیلتر در صورت موجود بودن
if (!empty($filter)) {
$postsQuery->where('title', 'like', '%' . $filter . '%');
}
// اعمال مرتب‌سازی
$postsQuery->orderBy($sortBy, $sortDirection);
// گرفتن پست‌ها با پجینیشن
$posts = $postsQuery->paginate($perPage);
// ساخت meta و links برای pagination
$meta = [
'total' => $posts->total(),
'per_page' => $posts->perPage(),
'current_page' => $posts->currentPage(),
'last_page' => $posts->lastPage(),
'from' => $posts->firstItem(),
'to' => $posts->lastItem(),
];
$links = [
'first' => $posts->url(1),
'last' => $posts->url($posts->lastPage()),
'prev' => $posts->previousPageUrl(),
'next' => $posts->nextPageUrl(),
];
// بازگشت اطلاعات دسته‌بندی و پست‌ها
return response()->json([
'category' => new CategoryResource($category),
'posts' => PostResource::collection($posts),
'meta' => $meta,
'links' => $links,
], 200);
}
// ذخیره یک دسته‌بندی جدید
public function store(StoreCategoryRequest $request)
{
$category = Category::create($request->validated());
return new CategoryResource($category);
}
// به‌روزرسانی یک دسته‌بندی خاص
public function update(UpdateCategoryRequest $request, $id)
{
$category = Category::findOrFail($id);
$category->update($request->validated());
return new CategoryResource($category);
}
// حذف یک دسته‌بندی خاص
public function destroy($id)
{
$category = Category::findOrFail($id);
// قبل از حذف، مطمئن شوید که پست‌ها به دسته‌بندی دیگری منتقل شده‌اند یا حذف شوند
// برای سادگی، اینجا فقط دسته‌بندی را حذف می‌کنیم
$category->delete();
return response()->json(['message' => 'Category deleted successfully'], 200);
}
}

View File

@ -1,25 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class User extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @return array<int|string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
// اضافه کردن سایر فیلدهای مورد نیاز
'email' => $this->email,
'created_at' => $this->created_at,
];
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @return array<int|string, mixed>
*/
public function toArray(Request $request): array
{
return parent::toArray($request);
}
}

View File

@ -1,18 +1,13 @@
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Blog\CategoryController;
use App\Http\Controllers\Blog\HomeController;
use App\Http\Controllers\Blog\PostController;
use App\Http\Controllers\Blog\TagController;
use App\Http\Controllers\Website\ServiceController;
use App\Http\Controllers\Website\AboutMeController;
use App\Http\Controllers\Website\ProjectController;
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
use App\Http\Controllers\Api\Blog\CategoryController;
use App\Http\Controllers\Api\Blog\HomeController;
use App\Http\Controllers\Api\Blog\PostController;
use App\Http\Controllers\Api\Blog\TagController;
use App\Http\Controllers\Api\Website\AboutMeController;
use App\Http\Controllers\Api\Website\ProjectController;
use App\Http\Controllers\Api\Website\ServiceController;
Route::middleware('throttle:60,1')->group(function () {
Route::prefix('website')->group(function () {