1

How do I associate other associations before saving "parent"? I have a car that have many other parts:

  • A car has many seats
  • A car has many floor mats
  • A car has one mirror
  • etc.

The thing is, if either the seats or floor mats has any defects then the car cannot be created:

$car = new Car(...);

// Many mats
$mats = [new Mat(..), new Mat(..)];

// One mirror
$mirror = new Mirror(..);

// I need to put them all together.
// This does not work
$car->saveMany([$mats, $mirror, $mats]);

// Does not work
$car->mats()->saveMany($mats);
$car->associate($mirror);

// Car should not be saved if either any of its associations have an error.
$car->save();

The docs mentioned nothing about this example when instantiating a new object then save its associations: HasMany, HasOne, BelongsTo etc

I've looked at these but cannot get my head around it:

How to "associate" "car's" associations by calling "save()"?

Brian Thompson
  • 13,263
  • 4
  • 23
  • 43
Sylar
  • 11,422
  • 25
  • 93
  • 166
  • 1
    You say *should not be saved if either any of its associations have an error*, but how are you checking for an error? Are you just letting it 500 if something is invalid? You cannot save a related model without the parent already existing in the database, you need to have an `id` of the parent in order for the linking to take place. I think the correct approach would be to do some comprehensive validation, and then if it passes create the models in the correct order (parent, then associations). – Brian Thompson Oct 26 '21 at 13:32
  • Hi @BrianThompson Correct. The issue is, I have a function that creates, say, "mats". If mat's creation fails, I have to find the "car" then delete it because I save that first then pass down its id. Maybe a validation is needed. – Sylar Oct 26 '21 at 13:36
  • 1
    Yes, what I'm suggesting is that you validate the `mat` data before you create the `car`. Then if validation passes, the `mat` creation should never fail. So you can just create the `car` then the `mat`. – Brian Thompson Oct 26 '21 at 13:43
  • Thank you. That's easily done. – Sylar Oct 26 '21 at 13:45

1 Answers1

0

I would suggest that you look into the validation functionallities of laravel. (https://laravel.com/docs/8.x/validation)

you can make nested validations, so for example if you want to validate the seats of a car you can make rules like this:

public function store(Request $request)
{
    $validated = $this->validate($request, [
        'name' => 'required|string',
        'model' => 'required|exists:car_models,name',

        'seats' => 'required|array',
        'seats.*.color' => 'required',
        'seats.*.width' => 'numeric',
        'seats.*.fabric' => 'required|string',
    ]);

    // create the car with all relation data

    return $car;
}

The validation could be done as shown above, or via form request validation (https://laravel.com/docs/8.x/validation#form-request-validation).

That way, you can be sure that the users input is valid and will work before any of the models are created. After that you should create the car and add all the relations after. I would however suggest that you use the eloquent relations instead, by doing that you can write something like

// Create relation model with array of data
$car->seats()->create($seatData);

// Create relation models with collection of data
$car->seats()->createMany($seatsDataCollection);
4ice
  • 171
  • 2
  • 11