phplaraveleloquent

Laravel Eloquent Query Builder on Pivot


I have a three tables post(Model: Post), user(Model: User) and post_user_pivot for votes. The Schema of my pivot table

Schema::create('post_user', function (Blueprint $table) {
        $table->id();
        $table->enum('type', ['up', 'down'])->default('up');
        $table->unsignedBigInteger('post_id');
        $table->unsignedBigInteger('user_id');
        $table->timestamps();
    });

Storing the votes using attach along with the type, up or down. Fetching the voters like following ways

$post->voters as $voter using foreach()

Each $voter consist of $user as usual. But what I want to see the current authenticated user is voted or not, and if voted the type of it(up or down) from voters as mentioned above. No iteration just query for that? Thanks!

I have tried this

$post->voters->find(auth()->user()->id)->wherePivot('type', '=', 'down');

Solution

  • in order to check if a user has voted for a post or not you need to define the reverse relation on the user model:

    public function votedPosts()
    {
        return $this->belongsToMany(Post::class, 'votes')
                    ->withPivot('vote')
                    ->withTimestamps();
    }
    

    than in your controller you can do something like this:

    class PostController extends Controller
    {
      public function index(Request $request)
      {
        /** @var User $auth */
        $auth = $request->user();
    
        $posts = Post::query()->paginate();
    
        // load user votes for current posts
        $currentVotes = $auth->votedPosts()
          ->whereIn('posts.id', $posts->pluck('id'))
          ->pluck('vote', 'post_id']);
        // resulting array of post_id => vote_type ('up' or 'down')
    

    and in view:

    @foreach($posts as $post)
      <div class="card">
        <div class="votes">
          <button class="@if(isset($currentVotes[$post->id]) && $currentVotes[$post->id] == 'up') active @endif" data-post="{{ $post->id }}" data-type="up">
          <button class="@if(isset($currentVotes[$post->id]) && $currentVotes[$post->id] == 'down') active @endif" data-post="{{ $post->id }}" data-type="down">
        </div>
      </div>
    @endforeach