Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Indirect modification of overloaded property App\Category::$thesizes has no effect

Tags:

php

laravel

For a webshop im trying to generate a table that looks like:

Tablename: category 1
productname     S   M   L   X  total
name1           1    0  1   3  5
name2           0    1  0   2  3


Tablename: category 2
productname     S   L   X  total
name5           1   1   3  5
name8           0   0   2  2

There is a table for each category, each category has his own sizes (table 2 has no size M for example). The tables show the amount of ordered products per size per product in each category.

In the application there is a model OrderProducts which are ordered products in each Order.

An OrderProduct has a ProductSize which is a junction table of the product sizes

A ProductSize has a Size (which contains the name of the size)

The first step im tryin to do is get all sizes/products for each category like:

    $order = Order::findOrFail($id);
    $products = OrderProduct::where('orders_id',$id)->get();

    $categories = Category::all();
    //get sizes and products per category
    foreach($categories as $cat)
    {
        $cat->thesizes= array();
        $cat->theprodcts= array();
        foreach($products as $product)
        {
            if($product->productSize->product->category_id == $cat->id)
            {
                array_push($cat->thesizes,$product->productSize);
                array_push($cat->theprodcts,$product);
            }

        }
        //make sure all values are unique (no dubbele sizes).
        $cat->theSizes = array_unique($cat->theSizes);
        $cat->theProducts = array_unique($cat->theProducts);
    }

When I run my code I get the following error:

Indirect modification of overloaded property App\Category::$thesizes has no effect

Why do I get this error and how should I solve it?

like image 308
Sven van den Boogaart Avatar asked Jul 19 '16 15:07

Sven van den Boogaart


2 Answers

This is because your Category class has the __get() and __set() magic methods implemented.

So line 7 ($cat->thesizes= array();) invokes Category::__set() and line 12 (array_push($cat->thesizes,$product->productSize);) invokes Category::__get() but not Category::__set(). So while you impelemented this with the intention of pushing values onto an array that you set on the Category, it won't work since array_push() is working on a return value and not the actual array stored in the Category.

There are a few ways to fix this. The most shortcut way is to change Category::__get() to return values by reference, which is done by using a sort-of type-hint on the function's return declaration

class Category
{
    public function &__get($key) {
        // body of function
    }
}

But this is probably not recommended for reasons I can go into if you're curious.

The more sensible approach, without significantly modifying your code at least, is to build the arrays within the scope of the loop and then add them to your Category objects

foreach ($categories as $cat) {
    // Scope local arrays here first
    $thesizes = array();
    $theproducts = array();

    foreach ($products as $product) {
        if ($product->productSize->product->category_id == $cat->id) {
            // Push to those local arrays
            array_push($thesizes, $product->productSize);
            array_push($theprodcts, $product);
        }
    }

    // Now assign them to the category object
    $cat->theSizes = array_unique($thesizes);
    $cat->theProducts = array_unique($theproducts);
}

If you want to go for bonus points, since this is Laravel and your return values are collections, you can do something like this for a more sophisticated implementation

$categories = (Category::all())->map(function(Category $cat) {
    $cat->theProducts = $products
        ->filter(function(Product $product) use ($cat) {
            return $product->productSize->product->category_id == $cat->id;
        })
        ->unique();

    $cat->theSizes = $cat->theProducts
        ->map(function(Product $product) {
            return $product->productSize();
        })->unique();
});
like image 132
Peter Bailey Avatar answered Oct 06 '22 00:10

Peter Bailey


Following trick has worked for me

public function methods(){
     //other logics
     ...
    $result = json_decode(json_encode($result));

    $result->someProp = (object)[];
    $result->someProp->another = 'test';

    return response()->json($result);
}
like image 33
Santosh Kumar Avatar answered Oct 05 '22 23:10

Santosh Kumar