yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.24k stars 6.9k forks source link

Dealing with related AR models when loading, validating and saving #7585

Open RomeroMsk opened 9 years ago

RomeroMsk commented 9 years ago

I suggest to add functionality of loading, validating and saving related models when calling appropriate methods. Similar to #6664, but more complex. Let's say, we have models Order and Item, where Order has many Items. When loading data of Order from form or request body (REST), we want to load also its Items. Then we need to validate both Order and Items and pass errors to form or REST response. And finally save (create or update) all of them, using transactions. I think, it's common case and many devs encountered it.

Now to make this work we need to write all this logic in Controller (actionCreate and actionUpdate) or in REST action classes:

  1. Start transaction.
  2. Call $order->load().
  3. Take an array of Item models (or make it by creating several models) and call Item::loadMultiple() for an array or call $item->load() for each Item from request.
  4. Call validate() for Order and validate() for each Item or validateMultiple() for all models.
  5. Call save() for all models.
  6. Commit transaction.

Or another way is to override load(), validate(), create(), update() (and maybe another methods) of parent model to work with related models. It is better, because we can have several places, where Orders are creating: frontend, backend, REST.

So we can make universal methods for all this routine to make user code easy and clear:

  1. Call $order->load() (here we can call another method like loadWithRelations() or make optional parameter to not deal with relations by default). We can use built-in ActiveRecord::transactions() mechanism here or create transaction forcibly.
  2. Call $order->save() (which will call $order->validate() internally).
RomeroMsk commented 9 years ago

Any thoughts?

creocoder commented 9 years ago

@RomeroMsk

Now to make this work we need to write all this logic in Controller

From MVC point of view this way is wrong always.

Or another way is to override load(), validate(), create(), update() (and maybe another methods) of parent model to work with related models.

Just use correct thick models appoach. If differs from overriding methods. You can use event wrappers to make code cleaner.

Also, workflow may be different, you describe just specific application case this is why universal solution is impossible. Transactions part for example is absollute wrong.

RomeroMsk commented 9 years ago

@creocoder, so you think, we can't make any universal mechanism even for part of this?

creocoder commented 9 years ago

@RomeroMsk Its already there for everything except loadWithRelations() by using correct thik models + relations setters. Last impossible because model may have 2+ relations with same model. Do you need example?

RomeroMsk commented 9 years ago

@creocoder, yes, it will be useful.

RomeroMsk commented 9 years ago

@creocoder, could you provide an example code?

creocoder commented 9 years ago

@RomeroMsk Will provide little later. Sorry, busy on work. If you want you can add my to Skype (creocoder) and we can talk about that issue.

RomeroMsk commented 9 years ago

The main problem I have for now is showing errors of related models. For example, in REST controller I need to pass these errors into response array. I can't find any native framework methods for this, so decide to attach errors of related models to main model. Any other variants?

cebe commented 9 years ago

related to #569

mootensai commented 9 years ago

https://github.com/mootensai/yii2-relation-trait