blog api created
This commit is contained in:
parent
4f101885a8
commit
d98bc7bbb0
121
app/Http/Controllers/Blog/CategoryController.php
Normal file
121
app/Http/Controllers/Blog/CategoryController.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Blog;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\CategoryResource;
|
||||||
|
use App\Http\Resources\PostResource;
|
||||||
|
use App\Models\Blog\Category;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class CategoryController extends Controller
|
||||||
|
{
|
||||||
|
// نمایش لیست دستهبندیها با صفحهبندی
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$categories = Category::with('posts')->paginate(10);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// دریافت پستهای مربوط به این دستهبندی به ترتیب جدیدترینها
|
||||||
|
$posts = $category->posts()->with(['category', 'tags', 'author'])
|
||||||
|
->orderBy('published_at', 'desc')
|
||||||
|
->paginate($perPage);
|
||||||
|
|
||||||
|
// بازگشت اطلاعات دستهبندی و پستها
|
||||||
|
return response()->json([
|
||||||
|
'category' => new CategoryResource($category),
|
||||||
|
'posts' => PostResource::collection($posts),
|
||||||
|
'pagination' => [
|
||||||
|
'total' => $posts->total(),
|
||||||
|
'per_page' => $posts->perPage(),
|
||||||
|
'current_page' => $posts->currentPage(),
|
||||||
|
'last_page' => $posts->lastPage(),
|
||||||
|
'from' => $posts->firstItem(),
|
||||||
|
'to' => $posts->lastItem(),
|
||||||
|
],
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ذخیره یک دستهبندی جدید
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'name' => 'required|string|max:255|unique:categories,name',
|
||||||
|
'slug' => 'required|string|unique:categories,slug',
|
||||||
|
'description' => 'required|string',
|
||||||
|
'short_description' => 'nullable|string|max:500',
|
||||||
|
'image' => 'nullable|url',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json($validator->errors(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = Category::create($validator->validated());
|
||||||
|
|
||||||
|
return new CategoryResource($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// بهروزرسانی یک دستهبندی خاص
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$category = Category::findOrFail($id);
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'name' => 'sometimes|required|string|max:255|unique:categories,name,' . $category->id,
|
||||||
|
'slug' => 'sometimes|required|string|unique:categories,slug,' . $category->id,
|
||||||
|
'description' => 'sometimes|required|string',
|
||||||
|
'short_description' => 'nullable|string|max:500',
|
||||||
|
'image' => 'nullable|url',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json($validator->errors(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$category->update($validator->validated());
|
||||||
|
|
||||||
|
return new CategoryResource($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// حذف یک دستهبندی خاص
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
$category = Category::findOrFail($id);
|
||||||
|
// قبل از حذف، مطمئن شوید که پستها به دستهبندی دیگری منتقل شدهاند یا حذف شوند
|
||||||
|
// برای سادگی، اینجا فقط دستهبندی را حذف میکنیم
|
||||||
|
$category->delete();
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Category deleted successfully'], 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Http/Controllers/Blog/HomeController.php
Normal file
52
app/Http/Controllers/Blog/HomeController.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\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),
|
||||||
|
'most_viewed_posts' => PostResource::collection($mostViewedPosts),
|
||||||
|
'random_posts' => PostResource::collection($randomPosts),
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
127
app/Http/Controllers/Blog/PostController.php
Normal file
127
app/Http/Controllers/Blog/PostController.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Blog;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\PostResource;
|
||||||
|
use App\Models\Blog\Post;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
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'); // جهت پیشفرض: نزولی
|
||||||
|
|
||||||
|
// دریافت پارامترهای صفحهبندی از درخواست
|
||||||
|
$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 برمیگرداند
|
||||||
|
|
||||||
|
// بازگشت پست و پستهای مرتبط به صورت JSON با استفاده از منابع
|
||||||
|
return response()->json([
|
||||||
|
'post' => new PostResource($post),
|
||||||
|
'related_posts' => PostResource::collection($post->relatedPosts->sortByDesc('published_at')->take(5)), // بازگشت ۵ پست مرتبط جدیدترین
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ذخیره یک پست جدید
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'title' => 'required|string|max:255',
|
||||||
|
'body' => 'required|string',
|
||||||
|
'excerpt' => 'nullable|string|max:500',
|
||||||
|
'slug' => 'required|string|unique:posts,slug',
|
||||||
|
'author_id' => 'required|exists:users,id',
|
||||||
|
'category_id' => 'required|exists:categories,id',
|
||||||
|
'featured_image' => 'nullable|url',
|
||||||
|
'views' => 'nullable|integer',
|
||||||
|
'likes' => 'nullable|integer',
|
||||||
|
'published_at' => 'nullable|date',
|
||||||
|
'tags' => 'nullable|array',
|
||||||
|
'tags.*' => 'exists:tags,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json($validator->errors(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$post = Post::create($validator->validated());
|
||||||
|
|
||||||
|
if ($request->has('tags')) {
|
||||||
|
$post->tags()->attach($request->tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PostResource($post->load(['category', 'tags', 'author']));
|
||||||
|
}
|
||||||
|
|
||||||
|
// بهروزرسانی یک پست خاص
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$post = Post::findOrFail($id);
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'title' => 'sometimes|required|string|max:255',
|
||||||
|
'body' => 'sometimes|required|string',
|
||||||
|
'excerpt' => 'nullable|string|max:500',
|
||||||
|
'slug' => 'sometimes|required|string|unique:posts,slug,' . $post->id,
|
||||||
|
'author_id' => 'sometimes|required|exists:users,id',
|
||||||
|
'category_id' => 'sometimes|required|exists:categories,id',
|
||||||
|
'featured_image' => 'nullable|url',
|
||||||
|
'views' => 'nullable|integer',
|
||||||
|
'likes' => 'nullable|integer',
|
||||||
|
'published_at' => 'nullable|date',
|
||||||
|
'tags' => 'nullable|array',
|
||||||
|
'tags.*' => 'exists:tags,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json($validator->errors(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$post->update($validator->validated());
|
||||||
|
|
||||||
|
if ($request->has('tags')) {
|
||||||
|
$post->tags()->sync($request->tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PostResource($post->load(['category', 'tags', 'author']));
|
||||||
|
}
|
||||||
|
|
||||||
|
// حذف یک پست خاص
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
$post = Post::findOrFail($id);
|
||||||
|
$post->tags()->detach();
|
||||||
|
$post->relatedPosts()->detach();
|
||||||
|
$post->delete();
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Post deleted successfully'], 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
app/Http/Controllers/Blog/TagController.php
Normal file
72
app/Http/Controllers/Blog/TagController.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Blog;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\TagResource;
|
||||||
|
use App\Models\Blog\Tag;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
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(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'name' => 'required|string|max:255|unique:tags,name',
|
||||||
|
'slug' => 'required|string|unique:tags,slug',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json($validator->errors(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tag = Tag::create($validator->validated());
|
||||||
|
|
||||||
|
return new TagResource($tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// بهروزرسانی یک تگ خاص
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$tag = Tag::findOrFail($id);
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'name' => 'sometimes|required|string|max:255|unique:tags,name,' . $tag->id,
|
||||||
|
'slug' => 'sometimes|required|string|unique:tags,slug,' . $tag->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json($validator->errors(), 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tag->update($validator->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
app/Http/Resources/CategoryResource.php
Normal file
32
app/Http/Resources/CategoryResource.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class CategoryResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'name' => $this->name,
|
||||||
|
'slug' => $this->slug,
|
||||||
|
'description' => $this->description,
|
||||||
|
'short_description' => $this->short_description,
|
||||||
|
'image' => $this->image,
|
||||||
|
'posts_count' => $this->whenLoaded('posts', function () {
|
||||||
|
return $this->posts->count();
|
||||||
|
}),
|
||||||
|
'created_at' => Carbon::parse($this->created_at)->format('M d Y'),
|
||||||
|
'updated_at' => Carbon::parse($this->updated_at)->format('M d Y'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Http/Resources/PostResource.php
Normal file
35
app/Http/Resources/PostResource.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class PostResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'title' => $this->title,
|
||||||
|
'slug' => $this->slug,
|
||||||
|
'excerpt' => $this->excerpt,
|
||||||
|
'body' => $this->body,
|
||||||
|
'author' => new UserResource($this->author),
|
||||||
|
'category' => new CategoryResource($this->category),
|
||||||
|
'tags' => TagResource::collection($this->tags),
|
||||||
|
'featured_image' => $this->featured_image,
|
||||||
|
'views' => $this->views,
|
||||||
|
'likes' => $this->likes,
|
||||||
|
'published_at' => $this->published_at,
|
||||||
|
'created_at' => Carbon::parse($this->created_at)->format('M d Y'),
|
||||||
|
'updated_at' => Carbon::parse($this->updated_at)->format('M d Y'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Http/Resources/TagResource.php
Normal file
29
app/Http/Resources/TagResource.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class TagResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'name' => $this->name,
|
||||||
|
'slug' => $this->slug,
|
||||||
|
'posts_count' => $this->whenLoaded('posts', function () {
|
||||||
|
return $this->posts->count();
|
||||||
|
}),
|
||||||
|
'created_at' => Carbon::parse($this->created_at)->format('M d Y'),
|
||||||
|
'updated_at' => Carbon::parse($this->updated_at)->format('M d Y'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,6 +14,12 @@ class User extends ResourceCollection
|
|||||||
*/
|
*/
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return parent::toArray($request);
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'name' => $this->name,
|
||||||
|
// اضافه کردن سایر فیلدهای مورد نیاز
|
||||||
|
'email' => $this->email,
|
||||||
|
'created_at' => $this->created_at,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
@ -18,8 +19,8 @@ public function toArray(Request $request): array
|
|||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'email' => $this->email,
|
'email' => $this->email,
|
||||||
'created_at' => $this->created_at,
|
'created_at' => Carbon::parse($this->created_at)->format('M d Y'),
|
||||||
'updated_at' => $this->updated_at,
|
'updated_at' => Carbon::parse($this->updated_at)->format('M d Y'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
25
app/Models/Blog/Category.php
Normal file
25
app/Models/Blog/Category.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Blog;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Category extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'slug',
|
||||||
|
'description',
|
||||||
|
'short_description',
|
||||||
|
'image',
|
||||||
|
];
|
||||||
|
|
||||||
|
// رابطه با پستها
|
||||||
|
public function posts()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Post::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
99
app/Models/Blog/Post.php
Normal file
99
app/Models/Blog/Post.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Blog;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class Post extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'title',
|
||||||
|
'body',
|
||||||
|
'excerpt',
|
||||||
|
'slug',
|
||||||
|
'author_id',
|
||||||
|
'category_id',
|
||||||
|
'featured_image',
|
||||||
|
'views',
|
||||||
|
'likes',
|
||||||
|
'published_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
// رابطه با نویسنده
|
||||||
|
public function author()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'author_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// رابطه با دستهبندی
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Category::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// رابطه با تگها
|
||||||
|
public function tags()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Tag::class)->withTimestamps();
|
||||||
|
}
|
||||||
|
|
||||||
|
// پستهای مرتبط
|
||||||
|
public function relatedPosts()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Post::class, 'related_posts', 'post_id', 'related_post_id')->withTimestamps();
|
||||||
|
}
|
||||||
|
|
||||||
|
// اسکوپ فیلتر
|
||||||
|
public function scopeFilter($query, $filters)
|
||||||
|
{
|
||||||
|
if (isset($filters['category'])) {
|
||||||
|
$query->whereHas('category', function ($q) use ($filters) {
|
||||||
|
$q->where('slug', $filters['category']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters['tag'])) {
|
||||||
|
$query->whereHas('tags', function ($q) use ($filters) {
|
||||||
|
$q->where('slug', $filters['tag']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters['search'])) {
|
||||||
|
$query->where(function ($q) use ($filters) {
|
||||||
|
$q->where('title', 'like', '%' . $filters['search'] . '%')
|
||||||
|
->orWhere('body', 'like', '%' . $filters['search'] . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters['author'])) {
|
||||||
|
$query->whereHas('author', function ($q) use ($filters) {
|
||||||
|
$q->where('id', $filters['author']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters['published'])) {
|
||||||
|
$query->whereNotNull('published_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope برای اعمال مرتبسازی
|
||||||
|
*/
|
||||||
|
public function scopeSort($query, $sortField, $sortDirection = 'asc')
|
||||||
|
{
|
||||||
|
// بررسی اینکه فیلد مرتبسازی معتبر است یا خیر
|
||||||
|
$allowedSortFields = ['published_at', 'views', 'likes', 'title'];
|
||||||
|
if (in_array($sortField, $allowedSortFields)) {
|
||||||
|
$sortDirection = strtolower($sortDirection) === 'desc' ? 'desc' : 'asc';
|
||||||
|
$query->orderBy($sortField, $sortDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Models/Blog/Tag.php
Normal file
22
app/Models/Blog/Tag.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Blog;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Tag extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'slug',
|
||||||
|
];
|
||||||
|
|
||||||
|
// رابطه با پستها
|
||||||
|
public function posts()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Post::class)->withTimestamps();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,8 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
|
||||||
|
use App\Models\Blog\Post;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
@ -44,4 +46,9 @@ protected function casts(): array
|
|||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function posts()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Post::class, 'author_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
database/factories/Blog/CategoryFactory.php
Normal file
29
database/factories/Blog/CategoryFactory.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories\Blog;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
|
||||||
|
*/
|
||||||
|
class CategoryFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
$name = $this->faker->unique()->word;
|
||||||
|
return [
|
||||||
|
'name' => ucfirst($name),
|
||||||
|
'slug' => Str::slug($name),
|
||||||
|
'description' => $this->faker->paragraph,
|
||||||
|
'short_description' => $this->faker->sentence,
|
||||||
|
'image' => $this->faker->imageUrl(640, 480, 'business', true),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
41
database/factories/Blog/PostFactory.php
Normal file
41
database/factories/Blog/PostFactory.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories\Blog;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use App\Models\Blog\Post;
|
||||||
|
use App\Models\Blog\Category;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Tag>
|
||||||
|
*/
|
||||||
|
class PostFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected $model = Post::class;
|
||||||
|
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
$title = $this->faker->sentence;
|
||||||
|
return [
|
||||||
|
'title' => $title,
|
||||||
|
'body' => $this->faker->paragraphs(5, true),
|
||||||
|
'excerpt' => $this->faker->text(200),
|
||||||
|
'slug' => Str::slug($title) . '-' . $this->faker->unique()->numberBetween(1, 1000),
|
||||||
|
'author_id' => User::inRandomOrder()->first()->id ?? User::factory(),
|
||||||
|
'category_id' => Category::inRandomOrder()->first()->id ?? Category::factory(),
|
||||||
|
'featured_image' => $this->faker->imageUrl(800, 600, 'technics', true),
|
||||||
|
'views' => $this->faker->numberBetween(0, 1000),
|
||||||
|
'likes' => $this->faker->numberBetween(0, 500),
|
||||||
|
'published_at' => $this->faker->dateTimeBetween('-1 years', 'now'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
database/factories/Blog/TagFactory.php
Normal file
30
database/factories/Blog/TagFactory.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories\Blog;
|
||||||
|
|
||||||
|
use App\Models\Blog\Tag;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Tag>
|
||||||
|
*/
|
||||||
|
class TagFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected $model = Tag::class;
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
$name = $this->faker->unique()->word;
|
||||||
|
return [
|
||||||
|
'name' => ucfirst($name),
|
||||||
|
'slug' => Str::slug($name),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('categories', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name')->unique();
|
||||||
|
$table->string('slug')->unique();
|
||||||
|
$table->text('description');
|
||||||
|
$table->text('short_description')->nullable();
|
||||||
|
$table->string('image')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('categories');
|
||||||
|
}
|
||||||
|
};
|
||||||
29
database/migrations/2024_10_13_090821_create_tags_table.php
Normal file
29
database/migrations/2024_10_13_090821_create_tags_table.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('tags', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name')->unique();
|
||||||
|
$table->string('slug')->unique();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('tags');
|
||||||
|
}
|
||||||
|
};
|
||||||
39
database/migrations/2024_10_13_090833_create_posts_table.php
Normal file
39
database/migrations/2024_10_13_090833_create_posts_table.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('posts', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('title');
|
||||||
|
$table->text('body');
|
||||||
|
$table->text('excerpt'); // توضیحات مختصر
|
||||||
|
$table->string('slug')->unique();
|
||||||
|
$table->unsignedBigInteger('author_id'); // نویسنده
|
||||||
|
$table->foreign('author_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
|
$table->unsignedBigInteger('category_id'); // دسته بندی
|
||||||
|
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
|
||||||
|
$table->string('featured_image')->nullable(); // تصویر شاخص
|
||||||
|
$table->integer('views')->default(0); // تعداد بازدید
|
||||||
|
$table->integer('likes')->default(0); // تعداد لایک
|
||||||
|
$table->timestamp('published_at')->nullable(); // تاریخ انتشار
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('posts');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('post_tag', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('post_id');
|
||||||
|
$table->unsignedBigInteger('tag_id');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// ایجاد کلیدهای خارجی
|
||||||
|
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
|
||||||
|
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
|
||||||
|
|
||||||
|
// جلوگیری از ورود تکراری
|
||||||
|
$table->unique(['post_id', 'tag_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('post_tag');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('related_posts', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('post_id');
|
||||||
|
$table->unsignedBigInteger('related_post_id');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// ایجاد کلیدهای خارجی
|
||||||
|
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
|
||||||
|
$table->foreign('related_post_id')->references('id')->on('posts')->onDelete('cascade');
|
||||||
|
|
||||||
|
// جلوگیری از ورود تکراری
|
||||||
|
$table->unique(['post_id', 'related_post_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('related_posts');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\AboutMe;
|
use App\Models\AboutMe;
|
||||||
use App\Models\Skill;
|
use App\Models\Skill;
|
||||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
@ -15,45 +16,54 @@ public function run()
|
|||||||
{
|
{
|
||||||
// ایجاد رکورد AboutMe
|
// ایجاد رکورد AboutMe
|
||||||
$aboutMe = AboutMe::create([
|
$aboutMe = AboutMe::create([
|
||||||
'title' => 'About Me Title',
|
'title' => 'About Me',
|
||||||
'description' => 'This is a brief description about me.',
|
'description' => 'I am a web developer with over 10 years of experience in creating dynamic and user-centric web applications. Specializing in React and Next.js, I build scalable solutions that enhance performance and user experience. I enjoy tackling complex challenges, from improving legacy systems to developing new applications. My focus on frontend development and seamless backend integration allows me to deliver innovative results while staying current with industry trends.',
|
||||||
'image' => '/images/profile.png',
|
'image' => '/images/profile.png',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// ایجاد رکوردهای Skill
|
// ایجاد رکوردهای Skill
|
||||||
Skill::create([
|
Skill::create([
|
||||||
'title' => 'FrontEnd',
|
'title' => 'HTML & CSS (SASS, Responsive Design)',
|
||||||
'image' => '/images/frontend.png',
|
'image' => '/images/frontend.png',
|
||||||
'description' => 'UI design description.',
|
'description' => 'HTML & CSS (SASS, Responsive Design) description',
|
||||||
'link' => 'http://example.com/frontend',
|
'link' => 'http://example.com/frontend',
|
||||||
|
'percentage' => 95,
|
||||||
|
'about_me_id' => $aboutMe->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Skill::create([
|
||||||
|
'title' => 'React.js and Next.js Development',
|
||||||
|
'image' => '/images/backend.png',
|
||||||
|
'description' => 'React.js and Next.js Development description.',
|
||||||
|
'link' => 'http://example.com/backend',
|
||||||
|
'percentage' => 90,
|
||||||
|
'about_me_id' => $aboutMe->id,
|
||||||
|
]);
|
||||||
|
Skill::create([
|
||||||
|
'title' => 'Backend Development (RESTful APIs, Laravel)',
|
||||||
|
'image' => '/images/ui.png',
|
||||||
|
'description' => 'Backend Development (RESTful APIs, Laravel) description.',
|
||||||
|
'link' => 'http://example.com/ui',
|
||||||
|
'percentage' => 85,
|
||||||
|
'about_me_id' => $aboutMe->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Skill::create([
|
||||||
|
'title' => 'WordPress Development and Customization',
|
||||||
|
'image' => '/images/ux.png',
|
||||||
|
'description' => 'WordPress Development and Customization description.',
|
||||||
|
'link' => 'http://example.com/ux',
|
||||||
'percentage' => 90,
|
'percentage' => 90,
|
||||||
'about_me_id' => $aboutMe->id,
|
'about_me_id' => $aboutMe->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Skill::create([
|
Skill::create([
|
||||||
'title' => 'BackEnd',
|
'title' => 'Version Control (Git, GitHub)',
|
||||||
'image' => '/images/backend.png',
|
'image' => '/images/ux.png',
|
||||||
'description' => 'BackEnd description.',
|
'description' => 'Version Control (Git, GitHub) description.',
|
||||||
'link' => 'http://example.com/backend',
|
'link' => 'http://example.com/ux',
|
||||||
'percentage' => 80,
|
'percentage' => 80,
|
||||||
'about_me_id' => $aboutMe->id,
|
'about_me_id' => $aboutMe->id,
|
||||||
]);
|
]);
|
||||||
Skill::create([
|
|
||||||
'title' => 'UI Design',
|
|
||||||
'image' => '/images/ui.png',
|
|
||||||
'description' => 'UI design description.',
|
|
||||||
'link' => 'http://example.com/ui',
|
|
||||||
'percentage' => 70,
|
|
||||||
'about_me_id' => $aboutMe->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
Skill::create([
|
|
||||||
'title' => 'UX Design',
|
|
||||||
'image' => '/images/ux.png',
|
|
||||||
'description' => 'UX design description.',
|
|
||||||
'link' => 'http://example.com/ux',
|
|
||||||
'percentage' => 83,
|
|
||||||
'about_me_id' => $aboutMe->id,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
database/seeders/Blog/BlogSeeder.php
Normal file
46
database/seeders/Blog/BlogSeeder.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders\Blog;
|
||||||
|
|
||||||
|
use App\Models\Blog\Category;
|
||||||
|
use App\Models\Blog\Post;
|
||||||
|
use App\Models\Blog\Tag;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class BlogSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// انتخاب کاربر با id = 1
|
||||||
|
$user = User::find(1);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
// اگر کاربر با id 1 وجود نداشت، خطا ایجاد کن یا پیام مناسبی بده
|
||||||
|
$this->command->error('User with id 1 not found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد دستهبندیها
|
||||||
|
Category::factory(10)->create();
|
||||||
|
|
||||||
|
// ایجاد تگها
|
||||||
|
Tag::factory(20)->create();
|
||||||
|
|
||||||
|
// ایجاد پستها و تخصیص به کاربر با id = 1
|
||||||
|
Post::factory(50)->create([
|
||||||
|
'author_id' => $user->id, // اختصاص پستها به کاربر id 1
|
||||||
|
])->each(function ($post) {
|
||||||
|
// اختصاص تگها به پست
|
||||||
|
$tags = Tag::inRandomOrder()->take(rand(2, 5))->pluck('id');
|
||||||
|
$post->tags()->attach($tags);
|
||||||
|
|
||||||
|
// ایجاد پستهای مرتبط
|
||||||
|
$relatedPosts = Post::inRandomOrder()->where('id', '!=', $post->id)->take(rand(1, 3))->pluck('id');
|
||||||
|
$post->relatedPosts()->attach($relatedPosts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@
|
|||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Database\Seeders\Blog\BlogSeeder;
|
||||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
@ -16,11 +17,14 @@ public function run(): void
|
|||||||
// User::factory(10)->create();
|
// User::factory(10)->create();
|
||||||
|
|
||||||
User::factory()->create([
|
User::factory()->create([
|
||||||
'name' => 'Test User',
|
'name' => 'parsa aghayi',
|
||||||
'email' => 'test@example.com',
|
'email' => 'ceo@parsaaghayi.ir',
|
||||||
]);
|
]);
|
||||||
$this->call([
|
$this->call([
|
||||||
|
AboutMeSeeder::class,
|
||||||
ProjectSeeder::class,
|
ProjectSeeder::class,
|
||||||
|
ServiceSeeder::class,
|
||||||
|
BlogSeeder::class
|
||||||
// دیگر seeders
|
// دیگر seeders
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,28 +15,28 @@ public function run()
|
|||||||
{
|
{
|
||||||
$services = [
|
$services = [
|
||||||
[
|
[
|
||||||
'title' => 'UI/UX',
|
'title' => 'Custom Web Development',
|
||||||
'description' => 'Lorem ipsum dolor sit amet consectetur. Morbi diam nisi nam diam interdum',
|
'description' => 'We create tailored web applications that meet your unique business requirements, utilizing the latest technologies for optimal performance.',
|
||||||
'imageSrc' => '/images/ui-ux-vector.svg',
|
'imageSrc' => '/images/ui-ux-vector.svg',
|
||||||
'altText' => 'UI/UX Vector',
|
'altText' => 'Custom Web Development Vector',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Web Design',
|
'title' => 'Frontend Development',
|
||||||
'description' => 'Lorem ipsum dolor sit amet consectetur. Morbi diam nisi nam diam interdum',
|
'description' => 'Our frontend development services focus on crafting engaging, responsive user interfaces that enhance user experience across all devices.',
|
||||||
'imageSrc' => '/images/web-design-vector.svg',
|
'imageSrc' => '/images/web-design-vector.svg',
|
||||||
'altText' => 'Web Design Vector',
|
'altText' => 'Frontend Development Vector',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'App Design',
|
'title' => 'Backend Development',
|
||||||
'description' => 'Lorem ipsum dolor sit amet consectetur. Morbi diam nisi nam diam interdum',
|
'description' => 'We provide reliable backend development solutions, building robust server-side architectures and APIs to ensure smooth and secure application functionality.',
|
||||||
'imageSrc' => '/images/app-design-vector.svg',
|
'imageSrc' => '/images/app-design-vector.svg',
|
||||||
'altText' => 'App Design Vector',
|
'altText' => 'Backend Development Vector',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Graphic Design',
|
'title' => 'Website Maintenance and Support',
|
||||||
'description' => 'Lorem ipsum dolor sit amet consectetur. Morbi diam nisi nam diam interdum',
|
'description' => 'Our ongoing maintenance and support services keep your website updated, secure, and performing at its best, allowing you to focus on your core business.',
|
||||||
'imageSrc' => '/images/graphic-design-vector.svg',
|
'imageSrc' => '/images/graphic-design-vector.svg',
|
||||||
'altText' => 'Graphic Design Vector',
|
'altText' => 'Website Maintenance and Support Vector',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,10 @@
|
|||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\ProjectController;
|
use App\Http\Controllers\ProjectController;
|
||||||
use App\Http\Controllers\AboutMeController;
|
use App\Http\Controllers\AboutMeController;
|
||||||
|
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\SkillController;
|
use App\Http\Controllers\SkillController;
|
||||||
use App\Http\Controllers\ServiceController;
|
use App\Http\Controllers\ServiceController;
|
||||||
|
|
||||||
@ -16,3 +20,17 @@
|
|||||||
Route::resource('about-me', AboutMeController::class);
|
Route::resource('about-me', AboutMeController::class);
|
||||||
Route::resource('skills', SkillController::class);
|
Route::resource('skills', SkillController::class);
|
||||||
Route::apiResource('services', ServiceController::class);
|
Route::apiResource('services', ServiceController::class);
|
||||||
|
|
||||||
|
// مسیرهای بلاگ
|
||||||
|
Route::prefix('blog')->group(function () {
|
||||||
|
// پستها
|
||||||
|
Route::apiResource('posts', PostController::class);
|
||||||
|
// دستهبندیها
|
||||||
|
Route::apiResource('categories', CategoryController::class);
|
||||||
|
// تگها
|
||||||
|
Route::apiResource('tags', TagController::class);
|
||||||
|
// مسیر Homepage
|
||||||
|
Route::get('homepage', [HomeController::class, 'index']);
|
||||||
|
Route::get('categories/{slug}/posts', [CategoryController::class, 'getCategoryWithPosts']);
|
||||||
|
|
||||||
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user