0

Sorry I am new to Laravel and PHP. I have a web application code that I need to debug. I run the code, and it gives me ErrorException Trying to get property 'name' of non-object. I looked it up, and I know it's a common problem but I still cannot figure out what is causing this error. I already looked at this page and I don't understand: Reference - What does this error mean in PHP?

This is my controller code:

    function getActivity(){
    $lead_history = Lead::with('user','eventTypeTrashed','locationTrashed')->get();
    $event_history = Event::with('user','booking','contactus.event_type_trashed','booking.location_trashed')->get();
    
    $data = [];
    foreach ($lead_history as $key => $leads){
        if(count($leads->revisionHistory) > 0){
            foreach ($leads->revisionHistory as $history){
                $date_diff = \DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s'))->diff(\DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s',strtotime($history->updated_at))));
                if($date_diff->d > 0 ){
                    $date = $date_diff->d . ' days ago';
                } elseif($date_diff->h > 0){
                    $date = $date_diff->h . ' hours ago';
                }else{
                    $date = $date_diff->i . ' minutes ago';
                }
                $data[] = [
                    'id' => $leads->id,
                    'type' => 'lead',
                    'image' => $history->userResponsible()->user_avatar,
                    'user' => $history->userResponsible()->first_name .' '. $history->userResponsible()->last_name,
                    'user_id' => $history->userResponsible()->id,
                    'key' => ucwords(str_replace("_"," ",$history->fieldName())),
                    'client' => $leads->client_name,
                    'status' => 'update',
                    'old_value' =>$history->oldValue(),
                    'new_value' =>$history->newValue(),
                    'updated_at' => $history->updated_at,
                    'time_diff' =>$date,
                    'priority' => $leads->priority,
                    'location' => $leads->locationTrashed->name, // This line casuses an error
                    'event_type' => ($leads->eventTypeTrashed) ? $leads->eventTypeTrashed->name : ''
                ];

            }
        }
        $date_diff = \DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s'))->diff(\DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s',strtotime($leads->created_at))));
        if($date_diff->d > 0){
            $date = $date_diff->d . ' days ago';
        } elseif($date_diff->h > 0){
            $date = $date_diff->h . ' hours ago';
        }else{
            $date = $date_diff->i . ' minutes ago';
        }
        $data[] = [
            'id' => $leads->id,
            'type' => 'lead',
            'image' => $leads->user->user_avatar,
            'user' => $leads->user->first_name .' '. $leads->user->last_name,
            'user_id' => $leads->user->id,
            'key' => '',
            'client' => $leads->client_name,
            'status' => 'created',
            'updated_at' => $leads->created_at,
            'old_value' =>'',
            'new_value' =>'',
            'time_diff' =>$date,
            'priority' => $leads->priority,
            'location' => $leads->locationTrashed->name,
            'event_type' => ($leads->eventTypeTrashed) ? $leads->eventTypeTrashed->name : ''
        ];
    }

    foreach ($event_history as $key => $events){
        if(count($events->revisionHistory) > 0){
            foreach ($events->revisionHistory as $history){
                $date_diff = \DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s'))->diff(\DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s',strtotime($history->updated_at))));
                if($date_diff->d > 0){
                    $date = $date_diff->d . ' days ago';
                }elseif ($date_diff->h > 0){
                    $date = $date_diff->h . ' hours ago';
                }else{
                    $date = $date_diff->i . ' minutes ago';
                }
                $data[] = [
                    'id' => $events->id,
                    'type' => 'event',
                    'image' => $history->userResponsible()->user_avatar,
                    'user' => $history->userResponsible()->first_name .' '. $history->userResponsible()->last_name,
                    'user_id' => $history->userResponsible()->id,
                    'key' => ucwords(str_replace("_"," ",$history->fieldName())),
                    'client' => $events->booking->booking_name,
                    'status' => 'update',
                    'updated_at' => $history->updated_at,
                    'old_value' =>$history->oldValue(),
                    'new_value' =>$history->newValue(),
                    'time_diff' =>$date,
                    'priority' => $events->status,
                    'location' => $events->booking->location_trashed->name,
                    'event_type' => $events->contactus->event_type_trashed->name
                ];
            }
        }
        $date_diff = \DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s'))->diff(\DateTime::createFromFormat('Y-m-d H:i:s',date('Y-m-d H:i:s',strtotime($events->created_at))));
        if($date_diff->d > 0){
            $date = $date_diff->d . ' days ago';
        }elseif($date_diff->h > 0){
            $date = $date_diff->h . ' hours ago';
        }else{
            $date = $date_diff->i . ' minutes ago';
        }
        $data[] = [
            'id' => $events->id,
            'type' => 'event',
            'image' => ($events->user) ? $events->user->user_avatar : '',
            'user' => ($events->user) ? $events->user->first_name .' '. $events->user->last_name : '',
            'user_id' => ($events->user) ? $events->user->id : '',
            'key' => '',
            'client' => $events->booking->booking_name,
            'status' => 'created',
            'updated_at' => $events->created_at,
            'old_value' =>'',
            'new_value' =>'',
            'time_diff' => $date,
            'priority' => $events->status,
            'location' => $events->booking->location_trashed->name,
            'event_type' => $events->contactus->event_type_trashed->name
        ];
    }

    usort($data, function ($a, $b){
        $dateA = \DateTime::createFromFormat('Y-m-d H:i:s', $a['updated_at']);
        $dateB = \DateTime::createFromFormat('Y-m-d H:i:s', $b['updated_at']);
        return $dateB >= $dateA;
    });

    return $data;
}

Sorry if this is a bad question and please tell me if I need to include anything else

timothydao
  • 31
  • 1
  • 5
  • That lead probably doesn't have a locationTrashed. Make sure it exists before you try to access it. – aynber Sep 30 '21 at 18:10
  • How do I check? Do I use the `exists()` method? – timothydao Sep 30 '21 at 18:12
  • You can use a ternary, just like the line below it. – aynber Sep 30 '21 at 18:14
  • I used the ternary and the page runs. The problem is I want to make it have a value, how would I do that? – timothydao Sep 30 '21 at 18:18
  • `''` is an empty string. So if you want something else there, put it inside of those quotes – aynber Sep 30 '21 at 18:21
  • No, I want to fix it so that `locationTrashed->name` has the intended value. Would I need to change the database for that? – timothydao Sep 30 '21 at 18:24
  • Well, using the ternary would give it the intended value. It translates to "If $leads->locationTrashed exists, then use $leads->locationTrashed->name. If it does not exist, then send an empty string." The problem you're running into right now is that at least one lead does not have a locationTrashed, so you'll need to decide what to do in that case. – aynber Sep 30 '21 at 18:30

2 Answers2

0

This error occurs when there's no relational record found. Like in your code you've a relation "locationTrashed". When lead don't have any record related to it in location_trashed table it'll return error. In Laravel 8 you can return default model result if not results available against record or just simply use ($param ?? null).

Salman
  • 172
  • 2
  • 13
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 30 '21 at 23:14
0

You have a lot going on there! I have some suggestions that might make your life easier and your code cleaner. But first, the missing 'name' error...

'location' => $leads->locationTrashed->name,

Relationship Name

First thing I noticed about this relationship is the name should be 'location_trashed' instead of the camelCase 'locationTrashed'. In your other models, it is 'location_trashed', so make sure this is correct. I'll continue to reference it as locationTrashed, since this is what your current code reflects.

Finding the Cause

You're probably correct in identifying this line as causing the error. The issue is probably that the locationTrashed doesn't exist. You should look for the locationTrashed_id (or location_trashed_id) to figure out what the id is, and make sure the item exists in the database and hasn't been deleted.

Which Object Doesn't Exist?

If you aren't sure which object is causing the error, you can try dumping the object if the relationship doesn't exist. Laravel has convenient methods like has() and doesntHave() to make this easy. Put this right above the '$data[] = [' line.

https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

if($leads->doesntHave('locationTrashed')) {
    dd($leads);
}
$data[] = [
    'id' => $leads->id,
    'type' => 'lead',
...

This will let you see the object in question and determine which related 'locationTrashed' is missing.

Or... ignore it

If you need the relationship, use the above to try to figure it out. However, if the relationship isn't there because it doesn't always exist, set it to be ignored.

You can use an exists() method on the relationship to check if it exists.

'location' => ($leads->locationTrashed()->exists()) ? $leads->locationTrashed->name : ''

Now some suggestions:

Carbon for Dates

You should really look into using Carbon. This will take the 8 lines of code you have and reduce it to:

$date_diff = Carbon::parse($history->updated_at)->diffForHumans();

https://carbon.nesbot.com/docs/#api-humandiff

Attribute Accessors

Your user model has a first_name and last_name attribute that you're putting together to display their full name. If you do this often, you can set up an attribute accessor so you don't have keep doing it.

// User Model
public function getFullNameAttribute() {
    return $this->first_name.' '.$this->last_name;
}

// Controller
'user' => $history->userResponsible->full_name

https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators

Laravel Collections

When working with arrays, you can instead convert them into collections and take advantage of the many useful methods that it provides. Instead of ordering the data items yourself, you can use the sortBy() method:

$collection = collect($data)->sortBy('updated_at');
$collection = collect($data)->sortByDesc('updated_at'); // or descending

https://laravel.com/docs/8.x/collections

Ernesto Jaboneta
  • 71
  • 1
  • 1
  • 4