We need some more context. What is load()? What is getConversation()?
Trying to get property of non-object
Hi guys, I am really pulling my hair here. So I am pointing to a page and have the $id passed over as an HTTP param in the url path:
https://example.com/conversations/12345
So when I click a link with the above URL I get the error message
Trying to get property 'muid' of non-object on line: 26
When I refresh the page, the error is gone. When I try to dd $conversation->muid I get a string value.
public function load($id) {
$conversation = (new Conversation)->getConversation($id);
$moderator_uid = $conversation->muid;
$return['moderator'] = getUser($moderator_uid);
return $return;
}
Any hints are appreciated, I am really lost here.
Seems like this getConversation can return either null or non-object as it says, probably an array ?
What do you do in that method ? Make sure you are returning the correct object or add a check if the object exists for the given ID since you are not using any route model binding, and I am not sure if that's a Eloquent model, or just your custom DAO (data access object).
Basically getConversation loads a conversation by Id. An Eloquent model.
Everytime when I dd() it it is a valid eloquent model. When I dd $conversation->maid I get a string as it is a varchar column.
@ChristophAust well then add some code to start debugging
if (!$conversation) {
dd($id);
}
@Sinnbeck I did that, it just outputs the correct Id. I kept debugging further and even the attribute which throws the exception can be printed with dd().
@ChristophAust you can add further data in there. Like
dd(Conversation::find($id);
But consider showing your code. We can only give suggestions to how you can debug yourself. We have no way of guessing the problem
@Sinnbeck thank you I did not try to get the conversation directly.
@Sinnbeck the funny thing is, this here:
$conversation = ModelsConversation::find($id);
var_dump(gettype($conversation));
$moderator_uid = $conversation->muid;
It outputs me:
string(6) "object"
Trying to get property 'muid' of non-object on line: 30
I somehow suspect the Model itself, since it contains one of my historical sins. The model has an attribute "moderator" and a relation with the same name. Could this be causing the issue?
@ChristophAust Well start by checking the full error. It says it is on line 30 (and in what file). Are you sure it is this line?
$moderator_uid = $conversation->muid;
@Sinnbeck Yes, I am absolutely sure this is the line. Funny thing is, I can do this:
dd($conversation->muid);
But not this:
$moderator_uid = $conversation->muid;
@ChristophAust Can you show the Conversation model?
@Sinnbeck not sure which part is interesting to you, I removed some scopes which should not be of interest for debugging.
<?php
namespace App\Models;
use Carbon\Carbon;
class Conversation extends Model {
protected $table = 'conversation';
protected $appends = ['newmessages', 'chatpartnerid'];
protected $hidden = ['chatpartnerid', 'deletedby'];
protected $casts = ['blocked' => 'boolean', 'accepted' => 'boolean'];
protected $fillable = ['sender', 'recipient', 'muid', 'cuid', 'blocked', 'accepted', 'deletedby', 'deleted_at'];
public function messages() {
return $this->hasMany(\App\Models\ConversationMessage::class, 'conversation_id');
}
public function getNewmessagesAttribute() {
$last = $this->lastmessage;
if (! $last) {
if ($this->sender == getUid()) {
return false;
}
if ($this->sender != getUid()) {
return ($this->accepted == false) && ($this->blocked == false);
}
}
return ($last->seen == false) && ($last->sender != getUid());
}
public function getChatpartnerIdAttribute() {
if ($this->sender != getUid()) {
return $this->sender;
}
return $this->recipient;
}
public function senderUser() {
return $this->hasOne(\App\Models\AppUser::class, 'uid', 'sender')->select(['uid', 'nickname', 'age', 'avatar_approved', 'avatarfile']);
}
public function recipientUser() {
return $this->hasOne(\App\Models\AppUser::class, 'uid', 'recipient')->select(['uid', 'nickname', 'age', 'avatar_approved', 'avatarfile']);
}
public function sender() {
return $this->hasOne(\App\Models\AppUser::class, 'uid', 'sender')->select(['uid', 'nickname', 'age', 'avatar_approved', 'avatarfile']);
}
public function recipient() {
return $this->hasOne(\App\Models\AppUser::class, 'uid', 'recipient')->select(['uid', 'nickname', 'age', 'avatar_approved', 'avatarfile']);
}
public function scopeForUser($query, $uid) {
return $query->where('sender', '=', $uid)
->orWhere('recipient', '=', $uid);
}
[...]
public function lastmessage() {
return $this->hasOne(\App\Models\ConversationMessage::class, 'conversation_id')->latest();
}
}
@Sinnbeck ok, things are really weird now.
I got this:
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
// dd($conversation->muid);
$moderator_uid = $conversation->muid;
Still the same error.
@ChristophAust All looks fine.. Can you do this?
$conversation = Conversation::find($id);
$foo = $conversation->muid;
dd($conversation->muid);
@Sinnbeck Yes, I can.
@ChristophAust that would indicate that the error isn't in that code..
Try this next.
public function load($id) {
$conversation = (new Conversation)->getConversation($id);
$moderator_uid = $conversation->muid;
$return['moderator'] = getUser($moderator_uid);
dd($id);
return $return;
}
@Sinnbeck I can even do that as well. Still the stacktrace is pointing me to line 32 in this file and this is that line:
$moderator_uid = $conversation->muid;
This is the errormessage I get when I do this:
try{
$conversation = (new ModerationConversation)->load($id);
}catch( Exception $e){
return redirect()->to('moderation/inbox')
->with('errorMessage', $e->getTraceAsString());
}
@ChristophAust what is just below that code? What do you use $conversation for?
@Sinnbeck this is the whole function currently:
public function load($id) {
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
$moderator_uid = $conversation->muid;
$customer_uid = $conversation->cuid;
$return['moderated'] = getUser($moderator_uid);
$return['customer'] = getUser($customer_uid);
$return['customer']->isModerated = (new Profiles)->isModerated($moderator_uid);
$return['conversation'] = $conversation;
return $return;
}
The line that causes the error is:
$moderator_uid = $conversation->muid;
if I comment it out the same issue is here:
$customer_uid = $conversation->cuid;
I really cannot see the issue.
@christophaust what is the actual implementation of getConversation; it does not appear in the Conversation model that you shared; is there another Conversation class?
Are you showing the entire load method, what is the $return variable - it is not in scope in the load method??? I am wondering if you have omitted some code, and $conversation is being overwritten?
The names of classes are changing randomly Conversation, ModelConversation and ModerationConversation - what are we actually dealing with here?
@tykus there is another conversation Class. The implementation is that:
public function getConversation($id) {
$conversation = Conversation::where('id', '=', $id)
->with('sender')
->with('recipient')
->first();
if (! $conversation) {
return false;
}
$this->markMessagesRead($id, getUid());
return $conversation;
}
The names of classes are changing randomly Conversation, ModelConversation and ModerationConversation - what are we actually dealing with here?
They are actually "auto-aliased" by VSC, because I am desperately trying to find the issue and tried quite a lot.
@ChristophAust returning false but doing nothing to work with false in the consuming code?
public function load($id) {
$conversation = (new Conversation)->getConversation($id);
if (!$conversation) {
// do something e.g. return early
}
$moderator_uid = $conversation->muid;
// I still don't know what `$return` is?????
$return['moderator'] = getUser($moderator_uid);
return $return;
}
@tykus yes I am not really handling null. This is the faulty function:
public function load($id) {
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
$moderator_uid = $conversation->muid;
$customer_uid = $conversation->cuid;
$return['moderated'] = getUser($moderator_uid);
$return['customer'] = getUser($customer_uid);
$return['customer']->isModerated = (new Profiles)->isModerated($moderator_uid);
$return['conversation'] = $conversation;
return $return;
}
@tykus Oh an as you can see I even moved from Eloquent to query builder. I really just need to access those attributes :D
I am going crazy!
@ChristophAust first will return a stdClass object (which represents a Conversation record) or null - you have to code defensively...
public function load($id)
{
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
if (!$conversation) {
return;
}
$moderator_uid = $conversation->muid;
$customer_uid = $conversation->cuid;
// where is $return initialized???
$return['moderated'] = getUser($moderator_uid);
$return['customer'] = getUser($customer_uid);
$return['customer']->isModerated = (new Profiles)->isModerated($moderator_uid);
$return['conversation'] = $conversation;
return $return;
}
first will return a stdClass object (which represents a Conversation record) or null - you have to code defensively...
Yes, but I do not think this is the issue here, since if I dd() the var, I get an object. Trying to assign its value to a variable is where it crashes.
Oh and $return is not initialized at all. It is used straight away.
@ChristophAust are you working in a loop - dd will stop execution; the problem might not be the Conversation your retrieve on the first iteration of the loop? Try with dump() instead.
@tykus thanks for this info. I tried dump() and I get the uid printed out and then the exception, pointing to this file and this exact line again.
I think PHP is trolling me.
@ChristophAust what do you mean " I get the uid printed out" - how/where are you dumping the value?
Are you working in a loop???
@tykus when I do dump() of the attribute "muid" I get its value. The script keeps executing and after that I get the error message.
I do not work in a loop, no.
@ChristophAust this is bizarre....
So you're here; right?
public function load($id)
{
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
dump($conversation->muid);
$moderator_uid = $conversation->muid;
And if you move dump after the assignment; you get an error message again, or no???
public function load($id)
{
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
$moderator_uid = $conversation->muid;
dump($conversation->muid);
@tykus I get the dump value again and again the error message.
@ChristophAust wait... so that assignment worked then??? Are you still getting the same error message; or has the exception changed?
What happens if you progressively move the dump statement towards the bottom of that method; how far you you get before nothing is being dumped? Ultimately, can you get to dump the $return variable?
public function load($id)
{
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
$moderator_uid = $conversation->muid;
$customer_uid = $conversation->cuid;
$return['moderated'] = getUser($moderator_uid);
$return['customer'] = getUser($customer_uid);
$return['customer']->isModerated = (new Profiles)->isModerated($moderator_uid);
$return['conversation'] = $conversation;
return dump($return);
}
@tykus this is the funny part! I have done all that before. It perfectly works to dump it. Even $return is correctly filled.
When I call the load() method in try-catch block I get this error message.
@ChristophAust alright, this is impossible to diagnose without the wider context; we’re scratching around blindly otherwise
@ChristophAust don't suppose this is on github? Or you can recreate the issue in a test repo and put that up?
@tykus I am afraid I guess so, too. Especially since I do this in my project all over the place and this is the only method that keeps having this issue.
@Sinnbeck unfortunately it is a private repo.
@ChristophAust if you copy the method involved into a new laravel project, I don't assume it fails?
@Sinnbeck I think this is a bit tough to do. But what I tried is to copy the function and go step by step.
public function loadRaw($id) {
$conversation = DB::table('conversation')->where('id', '=', $id)->first();
var_dump($conversation->muid);
// $moderator_uid = $conversation->muid;
// $customer_uid = $conversation->cuid;
$return['moderated'] = getUser("28ac676f499feebc86ec702acf93c57d");
$return['customer'] = getUser("user1");
$return['customer']->isModerated = (new Profiles)->isModerated("28ac676f499feebc86ec702acf93c57d");
$return['conversation'] = $conversation;
return $return;
}
So as you see, I dump $conversation->muid and I get
string(32) "28ac676f499feebc86ec702acf93c57d"
However, the third line of the function itself threw an error, so I commented it out and took its value and put it statically. Like this it all works just fine. If I try to assign this value to a variable I get the error message.
@Sinnbeck Also I just tried to call this function in tinker and it executes without any error.
@Sinnbeck I think I got a bith further. So the code part which triggers the error is this here:
try{
$conversation = (new ModerationConversation)->loadRaw($convid);
}catch( Exception $e){
return redirect()->to('moderation/inbox')
->with('errorMessage', $e->getTraceAsString());
}
However it does not redirect me to "moderation/inbox" but keeps executing the method. So it seems it has the errorMessage in the session var from somewhere.
However, extending my code to that, fixes the issue for now it seems:
try{
session(['errorMessage' => null]);
$conversation = (new ModerationConversation)->loadRaw($convid);
}catch( Exception $e){
return redirect()->to('moderation/inbox')
->with('errorMessage', $e->getMessage());
}
Still I am not satisfied and scratching my head, because the stacktrace clearly sais the error is triggered in this part.
Please or to participate in this conversation.