Code Monkey home page Code Monkey logo

Comments (8)

staudenmeir avatar staudenmeir commented on July 17, 2024

Hi @ssglopes,

You can use getQuery() to get the underlying query builder and prevent the laravel_through_key column from being added:

public function tags()
{
    return $this->hasManyDeep(
        Tag::class,
        [Post::class, 'taggables'],
        ['author_id', ['taggable_type', 'taggable_id'], 'id'],
        [null, null, 'tag_id']
    );
}

$author->tags()
    ->getQuery()
    ->withoutGlobalScope(WithCountsScope::class)
    ->select('tags.id', 'tags.name')
    ->selectRaw('count(*) as "posts_count"')
    ->groupBy('tags.id', 'posts.author_id')
    ->get();

from eloquent-has-many-deep.

ssglopes avatar ssglopes commented on July 17, 2024

Hi @staudenmeir ,
thanks for your fast reply, that does indeed do the trick to get the correct query.
Only now I get this error:

"detail": "Call to undefined method Illuminate\\Database\\Eloquent\\Builder::addEagerConstraints()",

which is, i think, due to being now returned:

Illuminate\Database\Eloquent\Builder

instead of :

Staudenmeir\EloquentHasManyDeep\HasManyDeep

from eloquent-has-many-deep.

staudenmeir avatar staudenmeir commented on July 17, 2024

What does your eager loading query look like?

from eloquent-has-many-deep.

ssglopes avatar ssglopes commented on July 17, 2024

Hello @staudenmeir ,

The adjusted method by the recommendations you gave me causing the last above mentioned error now looks like this (regardless of its with and without ->get() on the end). It throws the error so I can not check the query in telescope so i used toRawSql() to see the query.

API url: /roles/3/users?include=tags

    public function tags()
    {      
        $test = $this->hasManyDeep(
                Tag::class,
                [Post::class, 'taggables'],
                ['author_id', ['taggable_type', 'taggable_id'], 'id'],
                [null, null, 'tag_id']
            )
            ->getQuery()
            ->withoutGlobalScope(WithCountsScope::class)
            //->withCustomThroughKeyCallback(fn() => ['tags.*', 'tags.id as laravel_through_key'])
            ->select('tags.id', 'tags.name')
            ->selectRaw('count(*) as "posts_count"')
            //->groupByRaw('"tags"."id", "posts"."author_id"');
            ->groupBy('tags.id')
            //->toRawSql()
            ->get()
            ;
        //dd($test);
        return $test;
    }

The query outputted by toRawSql():

select 
  "tags"."id", "tags"."name", count(*) as "posts_count" 
from 
  "tags" 
inner join "taggables" on "taggables"."tag_id" = "tags"."id" 
inner join "posts" on "posts"."id" = "taggables"."taggable_id" 
where 
  "taggables"."taggable_type" = 'App\Models\Post' 
and "tags"."deleted_at" is null 
and "tags"."active" = 1 
and "posts"."deleted_at" is null 
group by "tags"."id"

If I call the endpoint again but with old method I wrote initially can see the actual query in telescope:

    public function tags()
    {      
        $test = $this->hasManyDeep(
                Tag::class,
                [Post::class, 'taggables'],
                ['author_id', ['taggable_type', 'taggable_id'], 'id'],
                [null, null, 'tag_id']
            )
            //->getQuery()
            ->withoutGlobalScope(WithCountsScope::class)
            ->withCustomThroughKeyCallback(fn() => ['tags.*', 'tags.id as laravel_through_key'])
            //->select('tags.id', 'tags.name')
            ->selectRaw('count(*) as "posts_count"')
            //->groupByRaw('"tags"."id", "posts"."author_id"');
            ->groupBy('tags.id')
            //->toRawSql()
            //->get()
            ;
        //dd($test);
        return $test;
    }

Query from telescope:

select
  "tags"."id",
  "tags"."name",
  count(*) as "posts_count",
  "posts"."author_id" as "laravel_through_key"
from
  "tags"
  inner join "taggables" on "taggables"."tag_id" = "tags"."id"
  inner join "posts" on "posts"."id" = "taggables"."taggable_id"
where
  "taggables"."taggable_type" = 'App\Models\Post'
  and "posts"."author_id" in (2, 3)
  and "tags"."deleted_at" is null
  and "tags"."active" = 1
  and "posts"."deleted_at" is null
group by
  "tags"."id",
  "posts"."author_id"

But the query I actually want to have should look like this:

select
  "tags"."id",
  "tags"."name",
  count(*) as "posts_count"
from
  "tags"
  inner join "taggables" on "taggables"."tag_id" = "tags"."id"
  inner join "posts" on "posts"."id" = "taggables"."taggable_id"
where
  "taggables"."taggable_type" = 'App\Models\Post'
  and "posts"."author_id" in (2, 3)
  and "tags"."deleted_at" is null
  and "tags"."active" = 1
  and "posts"."deleted_at" is null
group by
  "tags"."id"

So I do achieve with getQuery() to adjust the query but itself but then it fails becuase of the fatal error. Which I suspect its because the adjusted method with getQuery() returns now a Builder instance instead of a Relation instance causing the fatal error to be trhown.

Thanks

from eloquent-has-many-deep.

staudenmeir avatar staudenmeir commented on July 17, 2024

Are you executing a query with ->with('tags') or ->load('tags')?

from eloquent-has-many-deep.

ssglopes avatar ssglopes commented on July 17, 2024

It hits this method https://github.com/laravel-json-api/eloquent/blob/01aa76ac3abcff97fd713e0bbf01c246f6dd1f5d/src/QueryBuilder/JsonApiBuilder.php#L227 which is a part of this package.

I put a dd() inside the below method and from that i can answer your question that it hits the ->with('')

    public function with($includePaths): self
    {
        $includePaths = IncludePaths::nullable($includePaths);

        $loader = new EagerLoader(
            $this->schemas,
            $this->schema,
            $includePaths,
        );
// ----------
        dd($includePaths);
// ----------
        $this->query->with($paths = $loader->getRelations());

        foreach ($loader->getMorphs() as $name => $map) {
            $this->query->with($name, static function(EloquentMorphTo $morphTo) use ($map) {
                $morphTo->morphWith($map);
            });
        }

        $this->eagerLoading = (!empty($paths) || !empty($map));
        $this->parameters->setIncludePaths($includePaths);

        return $this;
    }

LaravelJsonApi\Core\Query\IncludePaths {#2956 // vendor/laravel-json-api/eloquent/src/QueryBuilder/JsonApiBuilder.php:232
  -stack: array:1 [
    0 => 
LaravelJsonApi\Core\Query
\
RelationshipPath {#2959
      -names: array:1 [
        0 => "tags"
      ]
    }
  ]
}

from eloquent-has-many-deep.

staudenmeir avatar staudenmeir commented on July 17, 2024

Which I suspect its because the adjusted method with getQuery() returns now a Builder instance instead of a Relation instance causing the fatal error to be trhown.

Yes, the query is no longer relationship and can't be used for eager loading. I don't see a way to make your custom query with eager loading.

from eloquent-has-many-deep.

ssglopes avatar ssglopes commented on July 17, 2024

Ok thanks for your help regardless and will try to solve it in a different way.

from eloquent-has-many-deep.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.