2

I have a seemingly stupid and crazy situation. I have activity logs for users, my user model has this relationship in it:

public function activityLogs()
{
    return $this->hasMany(Log::class);
}

Pretty straight forward and when I check a single user object for all logs it works fine. So on one page I only want the last log recorded, I need the created_at date from it. When loading the users I run

$users = User::with(
    [
        'activityLogs' => function ($query) {
            $query->orderBy('created_at', 'desc')
                  ->limit(1);
        }
    ]
)

and this returns the last log as expected. When I want to get the date if I run

dd($users->first()->activityLogs()->first()->created_at->format("d/m/Y"));

I get a string output with the date as expected. However, when I try to do anything else with it, such as putting it into a variable or echoing it out I just get an error that activityLogs()->first() is not an object. The code in my view (inside a foreach ($users as $user) loop) is

{{ $user->activityLogs()->first()->created_at }}

and it just gives me the error

ErrorException (E_ERROR) Trying to get property of non-object (View: ROOT_PATH/resources/views/acp/partials/profiles.blade.php) (View: ROOT_PATH/resources/views/acp/partials/profiles.blade.php)

I've tried accessing activityLogs as both a collection and hasMany object. I've also tried converting the resultant JSON string back with json_decode but it still complains about not being an object.

Why? Why can I get the value perfectly fine when using dd but when I try anything else it's suddenly a JSON string? I've tried googling this but no matter what combination of words I try it just comes up with questions and guides on how to convert an Eloquent object into JSON, the opposite of what I want.

Styphon
  • 10,304
  • 9
  • 52
  • 86
  • From an answer I've seen here [Laravel HasMany](https://stackoverflow.com/questions/34571957/laravel-hasmany-method-not-working) have you tried `{{ $user->activityLogs->first()->created_at }}` – rbaskam Jun 28 '17 at 15:09
  • Yes, I have tried that as well. – Styphon Jun 28 '17 at 15:13
  • You're already loading the activity logs with `with`, so you don't need to do all that. Try looking at the dump for your `$user` to see if the activity log is in there. – aynber Jun 28 '17 at 15:16
  • Have you tried removing the first() from the foreach as you are already pulling it in – rbaskam Jun 28 '17 at 15:16
  • @aynber Yes, the expected information is there. – Styphon Jun 28 '17 at 15:17
  • @Rbaskam The foreach is only on the `users` collection. The `$user->activityLogs` is still a collection and so needs `first` running on it. – Styphon Jun 28 '17 at 15:18
  • If it's there, then you won't need first. When you load `$users`, you're already telling it to get only the first activity record for each user with the `with` function. Use the dump as a guide to get the activity log's date. – aynber Jun 28 '17 at 15:23
  • @aynber but because it's a `hasMany` relationship it returns a collection regardless, it's just a collection containing a single object. I know it is because if I do `dd($user->activityLogs)` it says it's a collection. – Styphon Jun 28 '17 at 15:29

3 Answers3

2

You need to check to make sure the user has a last activity. first() will return null if there aren't any logs. You should check for existence in your loop.

@foreach($user as $user)
    {{$user->activityLogs->count() > 0 ? $user->activityLogs->first()->created_at : 'User Has No Activity!'}}
@endforeach

Or use blade's @if/@else

@foreach($user as $user)
    @if($user->activityLogs->count() > 0)
        {{$user->activityLogs->first()->created_at}}
    @else 
        'User Has No Activity!'
    @endif  
@endforeach
Eric Tucker
  • 6,144
  • 1
  • 22
  • 36
  • It does, which is what I see when I use `dd($->activityLogs->first())` it shows me the correct record. – Styphon Jun 28 '17 at 16:30
  • That's just the first user but you're looping through a collection of users and one of the users in the collection (not the first user) doesn't have any activitylogs. – Eric Tucker Jun 28 '17 at 16:32
  • Of course, why didn't I think of that before. Thank you. – Styphon Jun 28 '17 at 17:47
0

There should be two ways you can go about it, since you're already eagerLoading it into a collection:

$user->activityLogs->first()->created_at

or

$user->activityLogs[0]->created_at
aynber
  • 22,380
  • 8
  • 50
  • 63
  • I've already tried that, I just get `Trying to get property of a non-object`. For some reason the Log object has been converted to a JSON string. Also you can't use `$user->activityLogs[0]` because it's a Laravel Collection, not an array. – Styphon Jun 28 '17 at 15:44
  • I tried it locally and it worked, but I am using an older version of Laravel, and that can make a difference. *shrug* – aynber Jun 28 '17 at 15:53
  • Thanks for trying at least :). – Styphon Jun 28 '17 at 15:54
0

I'm late for the party here, but the problem is that one of your activityLogs is null and that's why it's breaking for you. I had the same problem now and figured it out.

Gljiva
  • 1