Laravel-json-api: Include from url parameter doesn't do anything

Created on 29 Nov 2017  路  9Comments  路  Source: cloudcreativity/laravel-json-api

See here:

https://github.com/cloudcreativity/laravel-json-api/blob/6ea82034f235665de826f9d9eaba19f267a83294/src/Store/EloquentAdapter.php#L197-L202

The $includePaths extracted from the URL are not used at all.

Also, I don't think the default $this->with that _is_ there will do anything either, as the $query parameter is not returned and used, nor is it passed by reference.

question

All 9 comments

Hi!

$includePaths is provided as an argument so child classes can overload the method and work out the model with paths using the query include paths. So this is intentional.

When objects are passed as arguments, they point to the same object so the query object passed to this method is modified.

When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
http://php.net/manual/en/language.oop5.references.php

How would one go about overloading the adapter with() method so it's useful though? As it's not an eloquent builder, but a simple query builder, calling with() has no effect.

For example, I'd like to filter something by a field on a parent table and finding it virtually impossible. I've tried using join(), but the parent table has columns with the same name as the child table, so every child record ends up using the value from the parent table.

Edit - for example, here's what I'm doing (that isn't working):

protected function filter(Builder $query, Collection $filters)
{
    if ($filters->has('placement')) {
        // Urgh - ideally I'd like to do $query->where('placements.uuid', $filters['placement'])
        $placement = Placement::where(
            'uuid',
            $filters['placement']
        )->first();

        if ($placement) {
            $query->where('placement_id', $placement->id);
        } else {
            $query->where('id', 0);
        }
    }
    // How on earth can I get this to work? At the moment, all the dates have the same uuid as the placement!
    $query->join('placements', 'placements.id', 'dates.placement_id');
    $query->where('placements.status', '=', 'draft');
}

I feel if I can just crack this, I'll be golden!

@danherd it is an Eloquent builder that is passed in.

Have you tried to use the Eloquent whereHas method?

protected function filter(Builder $query, Collection $filters)
{
    $query->whereHas('placements', function ($q) use ($filters) {
        if ($filters->has('placement')) {
            $q->where('uuid', $filters->get('placement'));
        }

        $q->where('status', 'draft');
    });
}

An example of why you might want to overload the with method is if you only want to eager load a relationship if the client has asked to include it:

protected function with(Builder $query, Collection $includePaths)
{
    // add the default eager loads.
    parent::with($query, $includePaths);

    // only eager load the author relationship if the client is including it.
    if ($includePaths->contains('author')) {
        $query->with('author');        
    }
}

Immensely helpful as ever - cheers!

OK, how do I sort by fields in parent tables?

I've tried using $appends in the Eloquent model, but that doesn't work (they are only available in the resultant Eloquent model). Joining the parent table is out as it messes up any fields with the same name in both (this could be fixed by the routine that selects the fields specifying the table name).

The Eloquent relationship queries probably won't work for sorting (I haven't tried it before but from what I know about how it works, I don't think sorting is possible).

It sounds like you will need to do some sort of join. Do you know how you would write the query using either a normal query builder or the Eloquent query builder? If we work out that first I can show you how to incorporate it into the adapter.

GOT IT!

I discovered I can overwrite the select part of the query, so doing a join and only getting the fields from the joined table I actually need (and aliasing any duplicates - e.g. id, uuid), I can sort by whatever I want.

Here's the code for anyone else who's wondering about this:

protected function filter(Builder $query, Collection $filters)
{
    $query->selectRaw('practice_group_stats.*, practice_groups.uuid as practice_group_uuid, practice_groups.name, practice_groups.default')
        ->join('practice_groups', 'practice_groups.id', '=', 'practice_group_stats.practice_group_id');
...

And to sort:

protected function defaultSort(Builder $query)
{
    $query->orderBy('practice_groups.default', 'asc')
        ->orderBy('practice_groups.name', 'asc');
...

Above and beyond thanks for helping me on (deadline) weekend! Months of work hopefully coming to fruition very soon...

Glad you got this sorted! Doing a quick clean up of issues, so going to close this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lindyhopchris picture lindyhopchris  路  6Comments

JeanLucEsser picture JeanLucEsser  路  6Comments

nelson6e65 picture nelson6e65  路  3Comments

GregPeden picture GregPeden  路  4Comments

umbert-cobiro picture umbert-cobiro  路  4Comments