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?
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();
});
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With