Reputation: 2883
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
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
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
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