Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 5(.7) Organizing Model/Collection With Multiple Relations [closed]

I have the following Eloquent query that makes heavy use of relationships on models and it works.

Here it is:

$trip = ModelLocale::where("lang",$lang)
                    ->where("slug",$slug)
                    ->where('mainmodel_id',$id)
                    ->with(['mainmodel' => function ($query) use ($id)
                    {
                        $query
                            ->where('id', $id)
                            ->with(['convertedPrices' => function ($nestedQuery) use($id)
                            {
                                $nestedQuery
                                    ->where('model_id', $id)
                                    ->where('currency', Function::getCurrency());
                            }])
                            ->with(['othermodel','othermodel2', /** */, 'othermodel5']);
                    }])
                    ->first();

Anyway, this works and is just an illustration.

My problem is I get back a lot of nested relationships and it is a bit disorganized when it goes to the view.

I have another member of my team and either the eloquent relationships or specific way we make this query may change, but the view will more or less always need the same data. Therefore, I want to organize/sanitize this query and standardize it before passing it to my view.

Does this make sense?

I understand each return from Eloquent is an instance of this - Collection.

But I am having some issues dealing with the various methods here because when I dd() my collection I see so many properties and nests.

What is the recommended way to manipulate this big collection while keeping the integrity of the various relationship models? For example, this query would return a ModelLocale at the top, then a relationship property (among other properties that I don't need - like perPage and wasRecentlyCreated) with another model, then more nested relationships on this second model. I want to combine the first two models and just have relationships of the one parent.

So for example, when I dd I get:

-Model 1:
--Many properties
--Relations:
---Model 2
----Many properties
----Relations:
-----Model 3
-----Model 4
-----etc

Is there an easy way so when I am in the view, instead of...

$model->model_relationship->model_relationship->atrribute

...I can reorganize these around and merge the two first models? Or rename and map through the relations and attributes while ignoring the extraneous properties and make a very simple array of properties for the view?

Sorry this isn't extremely specific, I can't show exact values from my database and the point is that it will change... so I am looking for general guidance on this kind of reorganization of collections.

I am more comfortable with JSON than this, and I am bit intimidated by the structure of the collection, as I read somewhere collections "are like arrays on steroids".

Here is a sample of the collection:

ModelLocale {#246 ▼
  #fillable: array:1 [▶]
  #connection: "mysql"
  #table: "model_locales"
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: true
  +wasRecentlyCreated: false
  #attributes: array:8 [▼
    "id" => 580
    "main_model_id" => 290
    "title" => "Dolor dolores et hic."
    "slug" => "dolor-dolores-et-hic"
    "body" => "Enim consequuntur aliquam et iste aut incidunt corporis voluptates. Est sapiente doloribus est inventore delectus. Quia sequi doloremque nesciunt nulla non minu ▶"
    "lang" => "fj"
    "created_at" => "2019-01-16 19:17:43"
    "updated_at" => "2019-01-16 19:17:43"
  ]
  #original: array:8 [▶]
  #changes: []
  #casts: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: array:1 [▼
    "MainModel" => MainModel{#255 ▼
      #guarded: array:1 [▶]
      #hidden: array:2 [▶]
      #connection: "mysql"
      #table: "mainmodels"
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #attributes: array:16 [▼
        "id" => 290
        "model2_id" => 17
        "model3_id" => 0
        "model4_id" => 451
        "price" => "385.00"
        "created_at" => "2019-01-16 19:17:42"
        "updated_at" => "2019-01-16 19:17:43"
      ]
      #original: array:16 [▶]
      #changes: []
      #casts: []
      #dates: []
      #dateFormat: null
      #appends: []
      #dispatchesEvents: []
      #observables: []
      #relations: array:7 [▼
        "model3" => Model 3{#267 ▶}
        "model4" => Model 4{#264 ▶}
        "model5" => Model 5{#307 ▼
          #guarded: array:1 [▶]
          #connection: "mysql"
          #table: "model5s"
          #primaryKey: "id"
          #keyType: "int"
          +incrementing: true
          #with: []
          #withCount: []
          #perPage: 15
          +exists: true
          +wasRecentlyCreated: false
          #attributes: array:7 [▶]
          #original: array:7 [▶]
          #changes: []
          #casts: []
          #dates: []
          #dateFormat: null
          #appends: []
          #dispatchesEvents: []
          #observables: []
          #relations: []
          #touches: []
          +timestamps: true
          #hidden: []
          #visible: []
          #fillable: []
        }
        "model6" => Collection {#311 ▶}
        "model7" => Collection {#312 ▶}
        "model8" => null
        "model9" => Collection {#368 ▶}
      ]
      #touches: []
      +timestamps: true
      #visible: []
      #fillable: []
    }
  ]
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #guarded: array:1 [▶]
}

So I have ModelLocale, which has a relationship with MainModel which in turn has several relationships with the other models. But I just want a very simple (as much as possible) array of the attributes I care about - because again the nesting or relationships may change...

like image 542
Summer Developer Avatar asked Nov 07 '22 21:11

Summer Developer


1 Answers

There are two things I would suggest.

First, limit the query to eager load only specific columns when possible.

You may not always need every column from the relationships you are retrieving. For this reason, Eloquent allows you to specify which columns of the relationship you would like to retrieve:

$users = App\Book::with('author:id,name')->get();

Second, use a response transformer - see Eloquent: API Resources - to shape the data before sending the response. This guarantees the data you need in a set format.

These two things will both reduce the response payload and provide a sane, organized structure.

like image 193
Brian Lee Avatar answered Nov 14 '22 23:11

Brian Lee