BARNOWL
BARNOWL

Reputation: 3589

Laravel not getting Accessor Trying to get property on a non-object

I'm trying to get the value of a map object to check if a user made a rating or not.

{{ $book->rated }} is returning neither false or true.

in tinker

$book->getTypeAttribute(); PHP Notice: Trying to get property of non-object in /Applications/MAMP/htdocs/elirating/app/Book.php on line 40

This method needs to get the type of the rating, the default value is set to false

public function getTypeAttribute(){        
    return Rate::where('type', $this->attributes['id'])->where('user_id',auth()->user()->id) === self::RATED; 
}

Book.php

use Illuminate\Database\Eloquent\Model;
use willvincent\Rateable\Rateable;
use App\User;
use App\Rate;

class Book extends Model
{

    use Rateable;

    const RATED = "true";
    const NOT_RATED = "false";

    protected $fillable = [ 'user_id', 'title', 'description'];


    public function scopeGetBook($query, $book_name )
    {
        return $query->where('slug',  $book_name );
    }

    public function setTitleAttribute($value)
    {
        $this->attributes['title'] = $value;
        $this->attributes['slug'] = str_slug($value);

    }

    public function scopeGetBookUser($query, $user_id)
    {
        return $query->where('user_id',  $user_id )->first();
    }

    public function getTypeAttribute(){        
        return Rate::where('type', $this->attributes['id'])->where('user_id',Auth()->user()->id) === self::RATED; 
    }

Rate.php

<?php

namespace App;


use App\User;

use Illuminate\Database\Eloquent\Model;
use willvincent\Rateable\Rateable;

class Rate extends Model
{
    protected $fillable = [
        'user_id',
        'type',
        'rating'
    ];


    public $timestamps = false;

    protected $table = 'ratings';





}

BookController.php (this is how the type is being set, and how im trying to retrieve the value)

public function rate(Request $request, $book_id)
{

    $book = Book::find($book_id);
    $rating = $book->ratings()->where('user_id', auth()->user()->id)->first();

    if(is_null($rating)){
        $ratings = new Rating();
        $ratings->rating =  $request['rating'];
        $ratings->user_id = auth()->user()->id;
        $ratings->type = Book::RATED;
        $book->ratings()->save($ratings);




        return json_encode($book);

    }
    else{
       return response()->json(['status' => 'You already left a review']);
    }
}

  public function show($book_name)
{
    $books = Book::with('ratings')->GetBook($book_name)->get();


    $data = $books->map(function(Book $book){

        $book['rated'] = $book->getTypeAttribute();

        return $book;

    });

    return view('books.show', compact('data', $data));
}

HTML

  <div id="rateYo" data-rateyo-rating="{{  $book->userSumRating or 0}}" data-rateyo-read-only="{{ $book->rated }}" > ></div>

image(the read-only attribute needs to have either true of false) it doesn't show neither.

enter image description here

Upvotes: 1

Views: 1316

Answers (1)

Brian Lee
Brian Lee

Reputation: 18187

You need to call first or get on the query in the accessor:

return Rate::where(['type' => $this->getKey(), 'user_id' => auth()->id()])->first()

Also, when using accessors, you don't call the full function, as in getTypeAttribute, you only use the attribute name, type.

// wrong
$book['rated'] = $book->getTypeAttribute();

// right
$book['rated'] = $book->type;

However, I think what you should be doing to find if a user has left a rating is to use the exists or doesntExist query functions. For example:

// this will return true/false
public function getRatedAttribute()
{
    return Rate::where(['type' => $this->getKey(), 'user_id' => auth()->id()])->exists();
}

Append the attribute to the Book model:

// this will add the attribute to each book in the query result.
protected $appends = ['rated']; // or type

Then you can simply use:

$book->rated; // true if a rating exists, otherwise false.

Upvotes: 2

Related Questions