Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mhmmdva's avatar

How to resolving error : Trying to get property 'title' of non-object

I want to retrieve the title data from the proposal table, but I always get an error like this

progressReport model :

class ProgressReport extends Model
{
    use HasFactory;
    protected $guarded = ['id'];

    protected $casts = ['precentation' => 'date'];

    const PROGRESS_PATH = 'public/data/Report/Progress';
    const PROGRESS_REPORT = 'Progress';
    const FINAL_REPORT = 'Final';

    public function user()
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function proposal()
    {
        return $this->belongsTo(Proposal::class, 'proposal_id');
    }

    public function getPathFile($file)
    {
        $uploadFileName = Str::of($file->getClientOriginalName())->replace(' ', '-');
        $fileName = pathinfo($uploadFileName, PATHINFO_FILENAME);
        $fileExtension = $file->getClientOriginalExtension();
        $name = $fileName . '-' . now()->format('dmyhis') . '.' . $fileExtension;
        $fileUrl = $file->storeAs(ProgressReport::PROGRESS_PATH, $name);
        return $fileUrl;
    }
}

proposal model

class Proposal extends Model
{
    use HasFactory;

    const PROPOSAL_PATH = 'public/data/proposal';
    protected $guarded = ['id'];
	
	public function user()
    {
        return $this->belongsTo(User::class);
    }

	   public function progressReport()
    {
        return $this->hasMany(ProgressReport::class);
    }


}

user model

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    const LECTURER = 'Dosen';
    const ADMIN = 'Admin';
    const REVIEWER = 'Reviewer';
    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */

    public const LECTURER_PATH = "public/images/Lecturer";
    public const REVIEWER_PATH = "public/images/Reviewer";

    protected $table = 'users';
    protected $guarded = ['id'];
    protected $fillable = ['nidn', 'fullname', 'email', 'password', 'faculty', 'major', 'telp', 'birthdate', 'gender', 'address', 'image'];

public function proposal()
    {
        return $this->hasMany(Proposal::class);
    }

 public function progressReport()
    {
        return $this->hasMany(ProgressReport::class);
    }

}

progressreport controller

protected function store(LecturerReportRequest $request, ProgressReport $progress)
    {
        $this->authorize('isLecturer', auth()->user());

        $data = $request->validated();

        $status = ProgressReport::PROGRESS_REPORT;
        $user_id = auth()->user()->id;
        $fileName = ($request->hasFile('document_report')) ? $data['document_report'] = $progress->getPathFile($request->document_report) : "file not found";

        $data = [
            'fullname' => auth()->user()->fullname,
            'status_report' => $status,
            'document_report' => $fileName,
            'title' => $progress->proposal->title, // error from here
            'proposal_id' => $request->proposal_id, 
            'user_id' => $user_id,
        ];
      
        ProgressReport::create($data);

        Mail::to('[email protected]')->send(new SendProgressMail($data));

        return redirect()->route('lpp.lecturer-progress-report.index')->with('success', 'success!');
    }

0 likes
9 replies
mhmmdva's avatar

the condition of the relationship is like this,

  1. Every user has many progress reports
  2. Many progress reports are owned by each user
  3. One proposal contains many process reports
  4. There are many progress reports for each proposal

but is my relationship correct?

Snapey's avatar

when you have three arrows in a statement, you should think defensively since your app will always crash if the middle parameter is null.

The null coalesce operator is good for catching this

'title' => $progress->proposal->title ?? 'n/a',
mhmmdva's avatar

This code makes it error free, but the result is n/a . I want data on the contents of the title

mhmmdva's avatar

@Snapey

I use this method, the data can appear, but is this method correct?

$user_id = $request->user_id;
        $user = User::with('contract')->find($user_id);

        $proposal_id = $request->proposal_id;
        $proposal = Proposal::with('contract')->find($proposal_id);

        $data = [
            'fullname' => $user->fullname,
            'title' => $proposal->title,
        ];

Snapey's avatar

@mhmmdva test your relationships work with tinker.

Showing n/a means that $progress does not have an associated proposal record

Snapey's avatar

@mhmmdva So your code is identical to

        $user = User::find($request->user_id);
        $proposal = Proposal::find($request->proposal_id);
        $data = [
            'fullname' => $user->fullname,
            'title' => $proposal->title,
        ];

(don't know why you need contact)

What does this have to do with $progess ?

The other thing to note is that if you rely on hidden fields to pass data to the controller, these can be easily manipulated by the user to show any related records belonging to any user

mhmmdva's avatar

@Snapey sorry i'm typo

i mean like this :

		$user_id = $request->user_id;
        $user = User::with('progressReport')->find($user_id);

        $proposal_id = $request->proposal_id;
        $proposal = Proposal::with('progressReport')->find($proposal_id);

        $data = [
            'fullname' => $user->fullname,
            'title' => $proposal->title,
        ];
how to do the test if it's in Tinker?
gych's avatar

@mhmmdva In the code of your controller that you added to your initial post you need to make sure that the $progess variable that you sent to the store method already contains the property proposal with as value the proposal object.

If $progress doesn't include the full proposal object but only the $proposal_id you can do it like you showed in your last reply.

But be cautious because its possible that no proposal with that id is found, in that case $proposal->title will trigger an error because your trying to get the title from a variable that is null.

Also from what I see in your code you don't really need to add this: with('progressReport') Because you don't seem to use the data from progressReport and you create the report for the user and proposal at the end in the method.

To avoid that you can change your code like this:

		$user_id = $request->user_id;
        $user = User::find($user_id);

        $proposal_id = $request->proposal_id;
        $proposal = Proposal::find($proposal_id);

        $data = [
            'fullname' => $user->fullname,
            'title' => $proposal ? $proposal->title :  'N/A',
        ];
Snapey's avatar

Tinker

eg

>>> $proposal = Proposal::find(1)

use a valid id for a proposal

>>> $proposal->progressReport

check that the related progressReport(s) are returned.

ps. Anytime a relation can return multiple records, you should rename it to plural name so that you remember the response will be a collection. ie not progressReport but instead progressReports

1 like

Please or to participate in this conversation.