There is a Product model and the Category and ProductVariation models associated with it in different ways, which in turn is related to the Image and Property models.


DB structure http://freakytools.ru/storage/images/dbdes.png

class Product extends Model { public function variations() { return $this->hasMany('App\Models\ProductVariation'); } public function categories() { return $this->belongsToMany('App\Models\Category'); } } class ProductVariation extends Model { public function images() { return $this->hasMany('App\Models\Image'); } public function properties() { return $this->hasMany('App\Models\Property'); } } 

In Category and Image, all fields except name and image_link are hidden, respectively. In the controller, I display all Product with dependencies:

 class ProductsController extends Controller { public function index() { return Product::with(['categories', 'variations', 'variations.images', 'variations.properties'])->get(); } } 

As a result, I get an array of JSON:

 [ { "title": "Название продукта", "description": "Описание продукта", "priority": 0, "categories": [ { "title": "category1" }, { "title": "category2" } ], "variations": [ { "slug": "product1_slug", "price": 999, "count": 99, "images": [ { "image_link": "img/products/product1_1.png" }, { "image_link": "img/products/product1_2.png" }, { "image_link": "img/products/product1_3.png" } ], "properties": [ { "title": "Свойство 1", "value": "Значение свойства 1" }, { "title": "Свойство 2", "value": "Значение свойства 2" } ] } ] } ] 

It would be desirable in the fields 'categories' and 'images' to get an array of values, and not objects with a single field. I understand that you can live with it. But no: D The second day I dance with a tambourine. Thanks for participating!

UPD: While the implementation of this, but I do not want to believe that there is no more elegant way to solve the problem

 public function index() { $products = Product::with(['categories', 'variations', 'variations.images', 'variations.properties'])->get(); foreach ($products as $product) { $newCategories = []; $newImages = []; foreach ($product->categories as $category) array_push($newCategories, $category->title); foreach ($product->variations as $variation) { foreach ($variation->images as $image) array_push($newImages, $image->image_link); unset($variation->images); $variation->images = $newImages; } unset($product->categories); $product->categories = $newCategories; } return $products; } 
  • And why in category category_id, if there already is an id? - Stanislav Belichenko
  • And in essence, the question - so what exactly are you waiting for in the answer, a piece of rewritten laravel or some kind of native way to get what you want? As for me, the second option is unreal. Yes, and what's the problem, in fact, well, make a filter, which will then be reformatted by your rules. - Stanislav Belichenko
  • Well, only after -> get (), you can walk with methods, for example, pluck () or map () by converting each element after sampling, I do not think that it will take a lot of resources and will be time consuming. - Orange_shadow
  • @ Stanislav is not category_id in the 'categories' table? In the 'products_categories' category_id table for the many-to-many relationship. Or something wrong? I would like a solution at the functional level of the framework itself, but since it is impossible, invented crutches. - Freakytools
  • one
    @ Stanislav, finishing the frameworks and pull requests is not about me :) Regarding the categories, I must have misled both myself and you by the name of the table. It meant the use of tags for the possibility of classifying products. For example, sliced ​​long loaf can be classified as 'long loaf', 'from high-grade flour', 'with raisin', etc. Accordingly, 'with raisins' can be any other product. - Freakytools

1 answer 1

You can do through attributes:

 public function getCategoriesAttribute() { $value = []; return Cache::remember('getCategoriesAttribute'. $this->id, 1440, function() use ($value) { if($categories = $this->categories){ foreach($categories as $item){ $value[] = $item->title; } } return $value; }); } 

Then call as attribute, i.e. $ product_item-> categories

You can add 'categories' to the $ appends section, then for any call to the product model you will already have this attribute available

Read more here: https://laravel.com/docs/5.3/eloquent-mutators

  • if ($ categories = $ this-> categories) - is it specifically so, or is it still == necessary? :) - Stanislav Belichenko
  • one
    on purpose, so as not to pull the call of communication twice), check if there is a result, and then sort it out - fanamurov
  • one
    @fanamurov Thanks for the decision! I'll keep it in mind. Special thanks for the help with the appends section - it has become much more convenient. As for the arrays of single-line objects themselves, I climbed into Illuminate \ Support \ Collection and added the method simplify (), which recursively iterates over the current object and simplifies the array of single-line objects to an array of values. It looks neat: return $ this-> categories () -> get () -> simplify (); Thanks again for the help, the problem is solved! - Freakytools