framework: withoutGlobalScopes() ignored on HasManyThrough

  • Laravel Version: 5.5.33 - 5.6.15
  • PHP Version: 7.2

Description:

It seems like withoutGlobalScopes() and withoutGlobalScope() is ignored on HasManyThrough relations.

The query generated by the example below is:

SELECT
    *
FROM
    "comments"
INNER JOIN
    "posts" ON "post"."id" = "comments"."post_id"
WHERE
    "posts"."deleted_at" IS NULL
     AND "posts"."user_id" = ?

But should be:

SELECT
    *
FROM
    "comments"
INNER JOIN
    "posts" ON "post"."id" = "comments"."post_id"
WHERE
    "posts"."user_id" = ?

Steps To Reproduce:

class User extends Model
{
    public function comments()
    {
        return $this->hasManyThrough(Comment::class, Post::class)
            ->withoutGlobalScopes();
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 2
  • Comments: 18 (12 by maintainers)

Most upvoted comments

Almost two years later and there is still no way of doing this without using an external package 😕

Perhaps a better solution for this but this is how I got around this problem by extending the hasManyThrough relationship when I needed to extend the existing soft deletes trait and scope to work with a different database structure that doesnt use deleted_at columns with a timestamp

<?php

namespace App\Eloquent\Relations;

use Illuminate\Database\Eloquent;

class HasManyThrough extends Eloquent\Relations\HasManyThrough
{
    /**
     * Set the join clause on the query
     * @param \Illuminate\Database\Eloquent\Builder|null $query
     * @return void
     */
    protected function setJoin(Eloquent\Builder $query = null)
    {
        $query = ($query) ?: $this->query;
        $strForeignKey = $this->related->getTable().'.'.$this->secondKey;
        $query->join($this->parent->getTable(), $this->getQualifiedParentKeyName(), '=', $strForeignKey);

        if ($Scope = $this->parentSoftDeletes()) {
            // Eloquent hard codes $query->whereNull($this->parent->getQualifiedDeletedAtColumn())
            // on HasManyThrough which breaks everything, so use our instance of SoftDeletingScope instead
            $Scope->apply($query, $this->parent);
        }
    }

    /**
     * Determine whether close parent of the relation uses Soft Deletes
     * @return Eloquent\SoftDeletingScope|null
     */
    public function parentSoftDeletes()
    {
        $arrRemovedScopes = $this->query->removedScopes();
        // Get the instance of SoftDeletingScope on the parent model that requires it
        foreach ($this->parent->getGlobalScopes() as $strClassName => $Scope) {
            if (
                $Scope instanceof Eloquent\SoftDeletingScope &&
                !in_array($strClassName, $arrRemovedScopes)
            ) {
                return $Scope;
            }
        }
        // Seems unlikely but just in case SoftDeletes is on the model but the scope wasnt applied / failed to boot
        if (
            !in_array(Eloquent\SoftDeletingScope::class, $arrRemovedScopes) &&
            in_array(Eloquent\SoftDeletes::class, class_uses_recursive(get_class($this->parent)))
        ) {
            return new Eloquent\SoftDeletingScope();
        }
        return null;
    }
}

@yaim Your test scenario is different, the issue is about global scopes on the intermediate model.