
Xử lý Posts
1. Tạo Model
php artisan make:model Post --all//database\migrations\xxxx_xx_xx_xxxxxx_create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('user_id')->constrained();
$table->string('title');
$table->string('thumbnail')->nullable();
$table->string('slug')->unique();
$table->text('content');
$table->text('summary');
$table->boolean('published')->default(false);
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}//app\Models\Post.php
protected $fillable = [
'user_id',
'title',
'thumbnail',
'slug',
'content',
'summary',
'published',
'published_at',
];
public function user()
{
return $this->belongsTo(User::class);
}2. Thêm quan hệ trong model User
//app\Models\User.php
public function posts()
{
return $this->hasMany(Post::class);
}3. Thay đổi thư mục
//app\Http\Requests\Post\StorePostRequest.php (UpdatePostRequest.php)
namespace App\Http\Requests\Post;//app\Http\Controllers\PostController.php
use App\Http\Requests\Post\StorePostRequest;
use App\Http\Requests\Post\UpdatePostRequest;4. Factory
Faker formatters: https://github.com/fzaninotto/Faker
//database\factories\PostFactory.php
public function definition()
{
return [
'user_id' => User::factory(),
'title' => $this->faker->sentence,
'thumbnail' => $this->faker->imageUrl(640, 480),
'slug' => $this->faker->slug,
'content' => $this->faker->paragraphs(3, true),
'summary' => $this->faker->paragraph,
'published' => $this->faker->boolean,
'published_at' => $this->faker->dateTimeThisMonth(),
];
}5. Policy
//app\Policies\PostPolicy.php
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* @param \App\Models\User $user
* @return \Illuminate\Auth\Access\Response|bool
*/
public function viewAny(User $user)
{
return true;
}
/**
* Determine whether the user can view the model.
*
* @param \App\Models\User $user
* @param \App\Models\API\V1\Post $post
* @return \Illuminate\Auth\Access\Response|bool
*/
public function view(User $user, Post $post)
{
return true;
}
/**
* Determine whether the user can create models.
*
* @param \App\Models\User $user
* @return \Illuminate\Auth\Access\Response|bool
*/
public function create(User $user)
{
return true;
}
/**
* Determine whether the user can update the model.
*
* @param \App\Models\User $user
* @param \App\Models\API\V1\Post $post
* @return \Illuminate\Auth\Access\Response|bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
/**
* Determine whether the user can delete the model.
*
* @param \App\Models\User $user
* @param \App\Models\API\V1\Post $post
* @return \Illuminate\Auth\Access\Response|bool
*/
public function delete(User $user, Post $post)
{
return $user->id === $post->user_id;
}
/**
* Determine whether the user can restore the model.
*
* @param \App\Models\User $user
* @param \App\Models\API\V1\Post $post
* @return \Illuminate\Auth\Access\Response|bool
*/
public function restore(User $user, Post $post)
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*
* @param \App\Models\User $user
* @param \App\Models\API\V1\Post $post
* @return \Illuminate\Auth\Access\Response|bool
*/
public function forceDelete(User $user, Post $post)
{
return false;
}
}//app\Providers\AuthServiceProvider.php
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
Post::class => PostPolicy::class,
];6. Resquest
//app\Http\Requests\Post\StorePostRequest.php
class StorePostRequest extends FormRequest
{
use ApiResponse;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'title' => 'required|string|max:255',
'user_id' => 'required',
'slug' => 'required',
'summary' => 'required',
'content' => 'required|string',
'thumbnail' => 'required|url',
'published' => 'required|boolean',
'published_at' => 'required',
];
}
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(
$this->validationErrorResponse(
'Validation failed',
$validator->errors()
)
);
}
}//app\Http\Requests\Post\UpdatePostRequest.php
class UpdatePostRequest extends FormRequest
{
use ApiResponse;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'title' => 'sometimes|required|string|max:255',
'content' => 'sometimes|required|string',
'thumbnail' => 'sometimes|required|url',
'published' => 'sometimes|required|boolean',
];
}
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(
$this->validationErrorResponse(
'Validation failed',
$validator->errors()
)
);
}
}7. Service
Tất cả các function xử lý logic nên được viết trong file service, và được gọi lại trong controller.
<?php
namespace App\Services;
class PostService
{
public function getData()
{
// Logic
}
}//app\Providers\AppServiceProvider.php
/**
* Register any application services.
*
* @return void
*/
public function register()
{
...
$this->app->bind(PostService::class, function ($app) {
return new PostService();
});
}8. Resource & Collection
php artisan make:resource PostCollection
php artisan make:resource PostResource//app\Http\Resources\PostResource.php
class PostResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'user_id' => $this->user_id,
'content' => $this->content,
'summary' => $this->summary,
'thumbnail' => $this->thumbnail,
'slug' => $this->slug,
'published' => $this->published,
'published_at' => $this->published_at,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}//app\Http\Resources\PostCollection.php
class PostCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'posts' => PostResource::collection($this->collection),
'meta' => [
'total' => $this->total(),
'per_page' => $this->perPage(),
'current_page' => $this->currentPage(),
'last_page' => $this->lastPage(),
'from' => $this->firstItem(),
'to' => $this->lastItem(),
],
];
}
}9. Controller
//app\Http\Controllers\PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use App\Traits\ApiResponse;
use App\Models\Post;
use App\Http\Requests\Post\StorePostRequest;
use App\Http\Requests\Post\UpdatePostRequest;
use App\Http\Resources\PostCollection;
use App\Http\Resources\PostResource;
use App\Services\PostService;
class PostController extends Controller
{
use ApiResponse;
private $postService;
public function __construct(PostService $postService)
{
$this->postService = $postService;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$posts = Post::with('user')->paginate($request->get('per_page', 15));
return $this->successResponse(
new PostCollection($posts),
'Posts retrieved successfully'
);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\StorePostRequest $request
* @return \Illuminate\Http\Response
*/
public function store(StorePostRequest $request)
{
$validated = $request->validated();
$post = new Post($validated);
$post->save();
return $this->createdResponse(
new PostResource($post),
'Post created successfully'
);
}
/**
* Display the specified resource.
*
* @param $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$post = Post::with('user')->find($id);
if (!$post) {
return $this->notFoundResponse('Post not found');
}
if (!Auth::user()->can('view', $post)) {
return $this->unauthorizedResponse('You do not own this post.');
}
return $this->successResponse(
new PostResource($post),
'Post retrieved successfully'
);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\UpdatePostRequest $request
* @param $id
* @return \Illuminate\Http\Response
*/
public function update(UpdatePostRequest $request, $id)
{
$post = Post::find($id);
if (!$post) {
return $this->notFoundResponse('Post not found');
}
if (!Auth::user()->can('update', $post)) {
return $this->unauthorizedResponse('You do not own this post.');
}
$validated = $request->validated();
$post->fill($validated);
$post->save();
return $this->successResponse(
new PostResource($post),
'Post updated successfully'
);
}
/**
* Remove the specified resource from storage.
*
* @param $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$post = Post::find($id);
if (!$post) {
return $this->notFoundResponse('Post not found');
}
$post->delete();
return $this->deletedResponse('Post deleted successfully');
}
}10. Seeder
Chạy seeder để tạo mẫu các dữ liệu đã được định nghĩa trong factory
//database\seeders\DatabaseSeeder.php
User::factory(5)->superAdmin()->hasPosts(25)->create();
User::factory(50)->admin()->hasPosts(25)->create();
User::factory(50)->hasPosts(25)->create();php artisan migrate:fresh --seed11. Route
//routes\api.php
//Private - auth
Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/{id}', [PostController::class, 'show']);
//Public - web
Route::post('/posts', [PostController::class, 'store']);
Route::put('/posts/{id}', [PostController::class, 'update']);
Route::delete('/posts/{id}', [PostController::class, 'destroy']);12. Postman

Share this article
Share: