malhobayyeb
malhobayyeb

Reputation: 2883

Why I am getting Trying to get property of non-object in Laravel Eloquent

I have the following function:

public function show($id){

    $product = Product::findOrFail($id);
    $product_image = $product->image->file_name.".".$product->image->file_extension;
    return json_encode(array_merge($product->toArray(), ["image" => $product_image]));

}

Given the id, it will return the following JSON:

{
  "id": 1,
  "parent_id": 0,
  "category_id": 0,
  "image": "1.png"
}

And I have the following function:

public function index() {

    return json_encode(Product::all());

}

Which will return the following JSON:

[
  {
    "id": 1,
    "parent_id": 0,
    "category_id": 0
  },
  {
    "id": 2,
    "parent_id": 0,
    "category_id": 0
  },
  {
    "id": 3,
    "parent_id": 0,
    "category_id": 0
  },
  {
    "id": 4,
    "parent_id": 0,
    "category_id": 0
  }
]

My functions are in a Controller class for my API in a Laravel project.

ProductsController extends Controller

Product is a Eloquent model.

What I am trying to achieve is to make index function returns the array with the image property. Here is my try:

public function index() {

    $products = Product::all();

    $productsWithImages = [];

    for($i = 0; $i < count($products); $i++) { 
        $product = $products[$i];

        $product_image = $product->image->file_name.".".$product->image->file_extension;

        $productsWithImages[] = array_merge($product->toArray(), ["image" => $product_image]);
    }

    return json_encode(productsWithImages);

}

However, I am getting the following error when I test my API:

Trying to get property of non-object

And it points to the following line:

$productsWithImages[] = array_merge($product->toArray(), ["image" => $product_image]);

Product model class:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\File;

class Product extends Model
{

    use SoftDeletes;

    protected $fillable = ['parent_id', 'category_id'];


    // this is for voyager
    public function categoryId() {
        return $this->belongsTo(ProductCategory::class);
    }

    // this is for voyager
    public function parentId() {
        return $this->belongsTo(self::class);
    }

    public function category() {

        return $this->belongsTo(ProductCategory::class);

    }

    public function parent() {

        return $this->belongsTo(Product::class);

    }


    public function files(){

        return $this->hasOne(File::class, 'file_name');

    }


    public function image() {

        return $this->files()->where('table_name', '=', 'products');

    }

}

Note: Above this line I have removed some output of Product properties for clarity.

Output of print_r($product):

App\Product Object
(
    [dates:protected] => Array
        (
            [0] => deleted_at
        )

    [fillable:protected] => Array
        (
            [0] => name
            [1] => parent_id
            [2] => category_id
            [3] => alternative_name
            [4] => critical_quantity
            [5] => allowed_increase
            [6] => maximum_purchase_quantity
            [7] => status
            [8] => sort
        )

    [connection:protected] => mysql
    [table:protected] => 
    [primaryKey:protected] => id
    [keyType:protected] => int
    [incrementing] => 1
    [with:protected] => Array
        (
        )

    [perPage:protected] => 15
    [exists] => 1
    [wasRecentlyCreated] => 
    [attributes:protected] => Array
        (
            [id] => 1
            [parent_id] => 0
            [category_id] => 0
            [name] => Apple
            [alternative_name] => 
            [critical_quantity] => 
            [allowed_increase] => 
            [maximum_purchase_quantity] => 
            [status] => 
            [sort] => 
            [created_at] => 
            [updated_at] => 2017-04-23 00:23:46
            [deleted_at] => 
        )

    [original:protected] => Array
        (
            [id] => 1
            [parent_id] => 0
            [category_id] => 0
            [name] => Apple
            [alternative_name] => 
            [critical_quantity] => 
            [allowed_increase] => 
            [maximum_purchase_quantity] => 
            [status] => 
            [sort] => 
            [created_at] => 
            [updated_at] => 2017-04-23 00:23:46
            [deleted_at] => 
        )

    [casts:protected] => Array
        (
        )

    [dateFormat:protected] => 
    [appends:protected] => Array
        (
        )

    [events:protected] => Array
        (
        )

    [observables:protected] => Array
        (
        )

    [relations:protected] => Array
        (
        )

    [touches:protected] => Array
        (
        )

    [timestamps] => 1
    [hidden:protected] => Array
        (
        )

    [visible:protected] => Array
        (
        )

    [guarded:protected] => Array
        (
            [0] => *
        )

    [forceDeleting:protected] => 
)

Upvotes: 0

Views: 3534

Answers (3)

Joseph Silber
Joseph Silber

Reputation: 219920

It seems like some of your products do not have an image attached to them.

public function index()
{
    return Product::all()->map(function ($product) {
        if ($image = $product->image) {
            $image = $image->file_name.'.'.$image->file_extension;
        }

        return $product->toArray() + compact('image');
    });
}

P.S. you don't have to convert to JSON. Laravel takes care of that automatically.

Upvotes: 1

MohamedSabil83
MohamedSabil83

Reputation: 1559

Try after change to this:

public function index() {

    $products = Product::all();
    $productsWithImages = [];

    foreach($products as $product) {
        $product_image = !(empty($product->image)) ? $product->image->file_name.".".$product->image->file_extension : '';
        $productsWithImages[] = array_merge($product->toArray(), ["image" => $product_image]);
    }

    return json_encode(productsWithImages);
}

Upvotes: 1

elvador
elvador

Reputation: 36

Use a combination of Mutators and the $appends property.

Add this to you model:

class Product extends Model
{
    // ...

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = ['image_path'];

    // ...

    /**
     * Get the full path for the product image.
     *
     * @return bool
     */
    public function getImagePath()
    {
        if ($this->image) {
            return $this->image->file_name . "." . $this->image->file_extension;
        }
        return ""; // or any other sensible default
    }

    // ...
}

You can read more about it in the documentation here: Eloquent: Serialization - Appending Values To JSON.

Upvotes: 1

Related Questions