Custom route model binding for each controller action

299 Views Asked by At

I am at the completion stage of my Laravel project. I am refactoring my code and query to the database, so I came to this question.

Schema migration for Post model:

Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
    $table->foreignId('category_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
    $table->string('title');
    $table->string('slug');
    $table->text('description')->fullText()->nullable();
    $table->longText('content')->nullable();

    $table->integer('views')->default(0);
    $table->string('thumbnail')->nullable();
    $table->text('keywords')->fullText()->nullable();
    $table->text('video_id')->fullText()->nullable();

    $table->string('role')->nullable();
    $table->boolean('active')->default(false);
    $table->boolean('ads')->default(false);

    $table->string('approved_status')->nullable();
    $table->timestamp('approved_at')->nullable();
    $table->timestamps();

    $table->index(['title', 'slug', 'active', 'ads', 'views', 'approved_status']);
});

Resourceful controller route:

Route::resource('/post', PostController::class);

I want to apply custom explicit binding resolution logic for each method in PostController.

// All column
public function show(Post $post)
{
    // Required "content" field here
}

// All column
public function edit(Post $post)
{
    // Required "content" field here
}

// Except "content" column
public function update(UpdatePostRequest $request, Post $post)
{
    // No need "content" field but it will update "content" field in next update query
}

// Except "content" column
public function destroy(Post $post)
{
    // No need "content" field
}

Also, I have other action methods for role, active, ads, approved_status, approved_at field for update, they are not granted permission to update easily in above method because this field is sensitive for me so I separated it to check more information before update. While updating this field, I don't want to inject "content" column field because it takes up a lot of memory.

// Except "content" column
public function edit2(Post $post)
{
    // No need "content" field
}

// Similary edit3, edit4, edit5 ... 

// Except "content" column
public function update2(Request $request, Post $post)
{
    // No need "content" field
}

// Similary update3, update4, update5 ...

Update

As @AloisoJunior said, I did and it works as he said but the ImplicitRouteBinding is initially triggered before the middleware is invoked so I don't want to implement a double query to achieve my goal.

BindPostModelMiddleware.php

public function handle(Request $request, Closure $next, $bind= "id")
{
    if ($request->route()->hasParameter('post')) {

        $select = array_diff((new Post)->getFillable(), ['content']);
        $select[] = "id";

        $post = Post::query()
            ->select($select)
            ->where($bind, $request->route()->parameter('post')?->$bind)
            ->firstOrFail();

        $request->route()->setParameter('post', $post);
    }
    return $next($request);
}

enter image description here

As docs, I should handle this with the resolveRouteBinding method but I should check each route and do it accordingly. So, Is there any other simple way to implement explicit binding which also works for dynamic route key name (Customizing the key).

0

There are 0 best solutions below