0

On my User model I have the following:

public function isOnline()
{
    return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}

The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.

In my controller I am doing the following:

    $builder = App\User::query()
        ->select(...fields I want...)
        ->with('isOnline')
        ->ofType($realm); 

    return $datatables->eloquent($builder)
        ->addColumn('info', function ($user) {
            return $user->isOnline;
        }
    })

However I don't get the value of 'rtype' for the users in the table and no errors.

miken32
  • 42,008
  • 16
  • 111
  • 154
  • Read docs of Laravel – Mahdi Younesi Jan 29 '18 at 18:39
  • If you care to expand on your answer it would be appreciated. I've read through the relationship and querying relationship docs and am looking for assistance as I cannot seemingly get the result I am looking for. Thanks. – ironchefbadass Jan 29 '18 at 20:09
  • [You do not need to mark questions as "SOLVED" via editing the title](//meta.stackexchange.com/a/116105/295637), or [posting updates/thanks in posts.](//meta.stackexchange.com/a/109959/295637). Simply add your own answer, and mark as accepted. Anything additional can be perceived as noise for future visitors. See: [Can I answer my own question?](//stackoverflow.com/help/self-answer). – Blue Jan 30 '18 at 14:45

2 Answers2

1

It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.

The correct approach is to only return the HasMany object from your method and it will be treated as a relation.

public function accounts()
{
    return $this->hasMany('App\Accounting', 'userid');
}

Then if you want an isOnline helper method in your App\User class you can add one like this:

public function isOnline()
{
    // This gives you a collection of \App\Accounting objects
    $usersAccounts = $this->accounts;

    // Do something with the user's accounts, e.g. grab the last "account"
    $lastAccount = $usersAccounts->last();
    if ($lastAccount) {
        // If we found an account, return the rtype column
        return $lastAccount->rtype;
    }

    // Return something else
    return false;
}

Then in your controller you can eager load the relationship:

$users = User::with('accounts')->get(['field_one', 'field_two]);

Then you can do whatever you want with each App\User object, such as calling the isOnline method.


Edit

After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.

So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:

// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');

This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns

Jonathon
  • 15,873
  • 11
  • 73
  • 92
  • Thanks for the input, greatly appreciated... I made some updates: https://pastebin.com/FCj4UTmT The issue I'm having now, is that $user->isOnline(); always returns "oops" (for debugging purposes) The isOnline method *should*, based on the user, query the accounting table for the most recent row (newest) and give the value for 'rtype' Right now, seemingly, it's not doing that... I tried to swap last() for latest('ts') (ts being my timestamp column) but that method isn't available. Thank you very very much for the assistance thus far. – ironchefbadass Jan 30 '18 at 13:22
  • So the following works but the controller bits feel super dirty, any advice there? https://pastebin.com/xyMKwFKz – ironchefbadass Jan 30 '18 at 14:00
  • All set, this is the final version that works well: https://pastebin.com/4nB1N30e Thank you for your help – ironchefbadass Jan 30 '18 at 14:32
  • Sorry, I've not been active today and hadn't seen your messages. No problem, glad you got it sorted :) – Jonathon Jan 30 '18 at 16:36
0

Thanks Jonathon

USER MODEL

public function accounting()
{
    return $this->hasMany('App\Accounting', 'userid', 'userid');
}

public function isOnline()
{
    $rtype = $this->accounting()
        ->latest('ts')
        ->limit(1)
        ->pluck('rtype')
        ->first();

    if ($rtype == 'Alive') {
        return true;
    }
    return false;
}

CONTROLLER

$builder = App\User::with('accounting:rtype')->ofType($filterRealm);

return $datatables->eloquent($builder)
    ->addColumn('info', function (App\User $user) {

    /*
    THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
    ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
    */

    $info[];

    if ($user->isOnline()) {
        $info[] = 'Online';
    } else {
        $info[] = 'Offline';
    }

    return implode(' ', $info);
})->make();