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

CookieMonster's avatar

laravel-sendResponse how to return object within object

I made a simple API to return category child which displays the JSON output like below:

[
{
"id": 14,
"name": "Pillows",
"slug": "pillows",
"parent_category_id": 1,
"created_at": "2020-04-30 09:33:31",
"updated_at": "2020-04-30 09:33:31"
},
{
"id": 15,
"name": "Bedsheets",
"slug": "bedsheets",
"parent_category_id": 1,
"created_at": "2020-04-30 09:33:31",
"updated_at": "2020-04-30 09:33:31"
},
{
"id": 16,
"name": "Mattresses",
"slug": "mattresses",
"parent_category_id": 1,
"created_at": "2020-04-30 09:33:31",
"updated_at": "2020-04-30 09:33:31"
},
{
"id": 17,
"name": "Bedframes",
"slug": "bedframes",
"parent_category_id": 1,
"created_at": "2020-04-30 09:33:31",
"updated_at": "2020-04-30 09:33:31"
}
]

The code of controller is basically like below:

    /**
     * Return category with products, product images, product sold by panels.
     */
    public function getChildCategory(Request $request, $categoryId)
    {
        try {
            $category = Category::where('id', $categoryId)
                ->firstOrFail();
        }
        // catch(Exception $e) catch any exception
        catch (ModelNotFoundException $e) {
            $error = 'The requested resource is not available.';
            return $this->sendError($error, 404);
        }

        $childCategories = $category->childCategories;


        return $this->sendResponse($childCategories);
    }

However, I want to add sub object within the object like below:

{
"id": 14,
"name": "Pillows",
"slug": "pillows",
"parent_category_id": 1,
"created_at": "2020-04-30 09:33:31",
"updated_at": "2020-04-30 09:33:31"

Product: (
color:black,
item:phone
)
},

How do I hardcode it so that I can display this for testing purposes?

0 likes
30 replies
drewdan's avatar

You could eager load them on the relation of the parent model.

$category = Category::where('id', $categoryId)->with('subcategory')
                ->firstOrFail();

That should make them available within the same object.

CookieMonster's avatar

The thing is right now it display JSON directly from the database, so I wanna add some stuff into it. I don't know how to alter the view.

CookieMonster's avatar

Though I am using laravel 5.8, not sure some of the stuff are outddated.

CookieMonster's avatar

Thanks, though I am new to using resource for API building, any way to speed up the process in the meantime that I could pump in some fake data?

It's just to get an idea how it looks like in the JSON.

Because right now, my class is extended ResponseController.

drewdan's avatar

The only other way I can think of doing it would be something like:

return response()->json([
	'category' => $category,
	'products' => [
		$category->product,
	],
]);

Or something along those lines, so you structure the returned data in the controller itself. Basically create an array, and return it. I am not sure what your sendResponse() method is. Can I see that?

CookieMonster's avatar

Right so it's calling the json response like the way you wrote above.

class ResponseController extends Controller
{
    public function sendResponse($response)
    {
        return response()->json($response, 200);
    }


    public function sendError($error, $code = 404)
    {
        $response = [
            'error' => $error,
        ];
        return response()->json($response, $code);
    }


    public function fakeResponse($response)
    {
        return response()->json(
            [
                'name' => 'Abigail',
                'state' => 'CA'
            ]
        );
    }
}

Basically, it returns $response which is the all the columns in the category table. But right now I want to add other tables columns inside so it would be like sub object within the object. How do I make it work?

drewdan's avatar
return $this->sendResponse([
	'category' => $category->childCategories,
	'products' => [
		$category->childCategories->product, //or whatever your relationship is called
	],
]);

If you did that, you would be returning an object with several child objects, your category one, and then whatever you wanted underneath, just structure it as an array. It will get returned as JSON.

CookieMonster's avatar

For category, I cant really called $category since it's in another class. How though?

drewdan's avatar

You can name it whatever you want, those names were just examples.

/**
     * Return category with products, product images, product sold by panels.
     */
    public function getChildCategory(Request $request, $categoryId)
    {
        try {
            $category = Category::where('id', $categoryId)
                ->firstOrFail();
        }
        // catch(Exception $e) catch any exception
        catch (ModelNotFoundException $e) {
            $error = 'The requested resource is not available.';
            return $this->sendError($error, 404);
        }

        $childCategories = $category->childCategories;


        return $this->sendResponse([
		'childCategory' => $childCategories,
		'another-key' => 'some more data here',
		'any-key' => 'put a variable or model relation here etc'
	]);
    }
drewdan's avatar

try running that snippet, and see what it returns (it should still work) you will then be able to see the returned json structure, and modify it to fit your needs accordingly.

CookieMonster's avatar

The output:

{
"0": {
"Product": "some more data here"
},
"childCategory": [
{
"id": 18,
"name": "Shoes Cabinets",
"slug": "shoes-cabinets",
"parent_category_id": 2,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44"
},
{
"id": 19,
"name": "Storage Shelves / Units",
"slug": "storage-shelves-units",
"parent_category_id": 2,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44"
},
{
"id": 20,
"name": "Book Cases",
"slug": "book-cases",
"parent_category_id": 2,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44"
},
{
"id": 21,
"name": "TV & Media Furnitures",
"slug": "tv-and-media-furnitures",
"parent_category_id": 2,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44"
},
{
"id": 22,
"name": "Wardrobes",
"slug": "wardrobes",
"parent_category_id": 2,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44"
},
{
"id": 23,
"name": "Kitchen Cabinets",
"slug": "kitchen-cabinets",
"parent_category_id": 2,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44"
}
]
}

My controller:

    public function getChildCategory(Request $request, $categoryId)
    {
        try {
            $category = Category::where('id', $categoryId)
                ->firstOrFail();
        }
        // catch(Exception $e) catch any exception
        catch (ModelNotFoundException $e) {
            $error = 'The requested resource is not available.';
            return $this->sendError($error, 404);
        }

        $childCategories = $category->childCategories;
        return $this->sendResponse([
            'childCategory' => $childCategories,
            [
                'Product' => 'some more data here',
            ]


        ]);

        // return $this->sendResponse($childCategories);
    }

Though, it should be in each of the child category inside, it has it's Product ( item=>etc,color=>etc....).

I didn't get what I want.

CookieMonster's avatar

I want it to return it like that:

 public function fakeResponse($response)
    {
        return response()->json(
            [
                'id' => '1',
                'name' => 'Pillows',
                'slug' => 'pillows',
                'parent_category_id' => '1',
                'created_at' => '2020-05-04 02:39:44',
                'updated_at' => '2020-05-04 02:39:44',
                'Products' => [
                    'item' => 'phone',
                    'color' => 'black'

                ]
            ]
        );
    }

Though the $childCategory is dynamic from db.

drewdan's avatar

what is the relation to the child category called? Product?

drewdan's avatar

Or better still, can you show your your childCategory model?

CookieMonster's avatar

My Category.php (model):

  /**
     * Get the category's parent if any.
     */
    public function parentCategory()
    {
        return $this->belongsTo('App\Models\Categories\Category', 'parent_category_id');
    }

    /**
     * Get all of the category's child if any.
     */
    public function childCategories()
    {
        return $this->hasMany('App\Models\Categories\Category', 'parent_category_id');
    }

    /**
     * Get all products belonging to a category.
     */
    public function products()
    {
        return $this->belongsToMany(
            'App\Models\Globals\Products\Product',
            'piv_category_product',
            'category_id',
            'product_id'
        );
    }
CookieMonster's avatar

I just shown, though I realized the childcategory is calling the same model itself. Forgive the code as it was written by a colleague.

drewdan's avatar

Try running:

public function getChildCategory(Request $request, $categoryId)
    {
        try {
            $category = Category::where('id', $categoryId)
                ->firstOrFail();
        }
        // catch(Exception $e) catch any exception
        catch (ModelNotFoundException $e) {
            $error = 'The requested resource is not available.';
            return $this->sendError($error, 404);
        }

        $childCategories = $category->childCategories->load('products');
        return $this->sendResponse($childCategories);

        // return $this->sendResponse($childCategories);
    }
CookieMonster's avatar

This is the output:


[
{
"id": 14,
"name": "Pillows",
"slug": "pillows",
"parent_category_id": 1,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44",
"products": []
},
{
"id": 15,
"name": "Bedsheets",
"slug": "bedsheets",
"parent_category_id": 1,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44",
"products": [
{
"id": 9,
"product_code": "BU0321 0101 0001",
"name": "Bedsheet Standard",
"name_slug": "bedsheet-standard",
"details": "100% Italian cotton come with quilt cover (140cm * 210cm, 210cm * 210cm, 247cm * 247cm)",
"description": "Suitable for single, small family and large family. ",
"quality_id": 1,
"product_rating": "5.0",
"created_at": "2020-05-04 02:39:45",
"updated_at": "2020-05-04 02:39:45",
"pivot": {
"category_id": 15,
"product_id": 9
}
},
{
"id": 10,
"product_code": "BU0321 0101 0002",
"name": "Bedsheet Moderate",
"name_slug": "bedsheet-moderate",
"details": "Super fine Italian cotton come with quilt cover (140cm * 210cm, 210cm * 210cm, 247cm * 247cm)",
"description": "Suitable for single, small family and large family. ",
"quality_id": 2,
"product_rating": "5.0",
"created_at": "2020-05-04 02:39:45",
"updated_at": "2020-05-04 02:39:45",
"pivot": {
"category_id": 15,
"product_id": 10
}
},
{
"id": 11,
"product_code": "BU0321 0101 0003",
"name": "Bedsheet Premium",
"name_slug": "bedsheet-premium",
"details": "Super fine Italian cotton sateen with border from Turkey (super fine embroidery with woven backing) come with quilt cover (140cm * 210cm, 210cm * 210cm, 247cm * 247cm)",
"description": "Suitable for single, small family and large family. ",
"quality_id": 3,
"product_rating": "5.0",
"created_at": "2020-05-04 02:39:45",
"updated_at": "2020-05-04 02:39:45",
"pivot": {
"category_id": 15,
"product_id": 11
}
}
]
},
{
"id": 16,
"name": "Mattresses",
"slug": "mattresses",
"parent_category_id": 1,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44",
"products": []
},
{
"id": 17,
"name": "Bedframes",
"slug": "bedframes",
"parent_category_id": 1,
"created_at": "2020-05-04 02:39:44",
"updated_at": "2020-05-04 02:39:44",
"products": []
}
]

Seems like it works but not quite sure from what sub-table is it calling?

drewdan's avatar
drewdan
Best Answer
Level 15

Laravel uses Eloquent Query Builder - this builds up a query based on the information you give it, and it returns a "Collection" A collection contains the information you requested.

So your first query:

$category = Category::where('id', $categoryId)->firstOrFail();

will return a collection of categories.

Your second query is on the relationship:

childCategories = $category->childCategories

This returns a collection which contains the childCategories. All I have done it told Eloquent, that I would like it to load the products relation on the category too. So the collection it returns will include the related products.

$childCategories = $category->childCategories->load('products');

I have told it to load products products being the relationship in the model you shared above.

This particular way of loading a relationship is called lazy loading. For more information about loading relationships on models, you can view the documents here: https://laravel.com/docs/7.x/eloquent-relationships#eager-loading

CookieMonster's avatar

There's something I am confused though, the end of the JSON, it has a pivot, what does it mean?

drewdan's avatar

It is referring to a pivot table. I am a little rusty with this myself to be honest, but, your products relationship on the model:

public function products()
    {
        return $this->belongsToMany(
            'App\Models\Globals\Products\Product',
            'piv_category_product',
            'category_id',
            'product_id'
        );
    }

This is a belongsToMany relationship, which means it can belong to multiple things. In this case it seems to belong to multiple categories, though I am not 100% on the design behind your model. But that is what the pivot is there for, it is holding keys for that relationship.

If you do not want these to be shown you can hide certain attributes on the model. More details here: https://laravel.com/docs/7.x/eloquent-serialization#hiding-attributes-from-json

CookieMonster's avatar

Yea apologies for the confusion as this design was not implemented by me. I have a hard time trying to process the relationship as well between the categories and it's attributes.

Thank you though for your solution. It works at least.

Please or to participate in this conversation.