ErnestsMillers's avatar

How do you save multiple records on model with hasMany() method?

I have a boat and boat tutorials. When creating a boat I can add up to 4 tutorials that have a YouTube link, title, description.

In controller I have everything for boat:

$boat = new Boat;
$boat->title = $request->title;
$boat->save();

Do I pass to the controller each field as: name="tutorial-links[]", name="tutorial-titles[]", name="tutorial-descriptions[]"? How do I validate if I want title,description required if link is preset.

BoatRequest.php

'tutorial_links'        => 'string',
'tutorial_titles'       => 'string|required_with:tutorial_links',
'tutorial_descriptions' => 'string|required_with:tutorial_links',

This doesn't work. Title, description gets passed as null if empty and when link is present.

And how would I loop through each in controller?

I know you can do saveMany on relationship such as $boat->tutorial()->saveMany, but how do I pass multiple and validate multiple to controller and then loop through them?

0 likes
5 replies
Cronix's avatar

Try using .* since they're arrays.

'tutorial_titles.*'       => 'string|required_with:tutorial_links',
'tutorial_descriptions.*' => 'string|required_with:tutorial_links',

https://laravel.com/docs/5.6/validation#validating-arrays

As far as looping, it's just like a normal array.

$titles = $request->tutorial_titles;
$descriptions = $request->tutorial_descriptions;

foreach ($titles as $key => $title) {
    echo $title;
    echo $descriptions[$key];
}

That assumes there is 1 title for each description and the arrays are present...

And for saving them to the related model: https://laravel.com/docs/5.6/eloquent-relationships#inserting-and-updating-related-models

1 like
ErnestsMillers's avatar

Just to clarify this is my form (simplified):

<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links[]') }}">
<input type="text" name="tutorial-titles[]">
<textarea name="tutorial-descriptions[]"></textarea>

<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links[]') }}">
<input type="text" name="tutorial-titles[]">
<textarea name="tutorial-descriptions[]"></textarea>

<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links[]') }}">
<input type="text" name="tutorial-titles[]">
<textarea name="tutorial-descriptions[]"></textarea>

<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links[]') }}">
<input type="text" name="tutorial-titles[]">
<textarea name="tutorial-descriptions[]"></textarea>

So the old() function doesn't work this way either.

And validating this against:

'tutorial_titles.*'       => 'string|required_with:tutorial_links',
'tutorial_descriptions.*' => 'string|required_with:tutorial_links',

Doesn't work.

Cronix's avatar

old() works, but the values are an array and not a single value. You also don't add the [] when using it, just the actual field name. So you need to check if it's present in the array.

tutorial_links also needs to be a .* in validation, since it's an array as well. I can't help with your actual validation as I haven't had that scenario using required_with.

<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links')[0] }}">
<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links')[1] }}">
<input type="text" name="tutorial-links[]" value="{{ old('tutorial-links')[2] }}">

etc.

1 like
ErnestsMillers's avatar

Okay all done

One problem was that in my form I had dashes, the validation works now like this:

'tutorial_links.*'        => 'string|nullable',
'tutorial_titles.*'       => 'string|required_with:tutorial_links.*|nullable',
'tutorial_descriptions.*' => 'string|required_with:tutorial_links.*|nullable',

And Controller looks like this:

$boat = new Boat;
$boat->name = $request->name;
$boat->save();

$inserted_boat = Boat::find($boat->id);
$links        = $request->tutorial_links;
$titles       = $request->tutorial_titles;
$descriptions = $request->tutorial_descriptions;

foreach ($links as $key => $link) {
            $tutorial = new FleetTutorial;
            $tutorial->link = $links[$key];
            $tutorial->title = $titles[$key];
            $tutorial->description = $descriptions[$key];
            $inserted_boat->tutorials()->save($tutorial);
}

Only problem is that I am saving every time all four tutorials whether or not they are filled, all of them being nullable, but to be honest it is the faulty front-end design I am working here. And I won't have many entries anyway.

Thank you, @Cronix

Cronix's avatar
Cronix
Best Answer
Level 67

Only problem is that I am saving every time all four tutorials whether or not they are filled

You can always do a check for the values and only insert if they have a value.

foreach ($links as $key => $link) {
    if ($link && $links[$key] && $titles[$key] && $descriptions[$key]) { // or however you need to determine whether to save this record
            $tutorial = new FleetTutorial;
            $tutorial->link = $links[$key];
            $tutorial->title = $titles[$key];
            $tutorial->description = $descriptions[$key];
            $inserted_boat->tutorials()->save($tutorial);
    }
}

You're welcome. Please mark the thread as solved if your issue is cleared up.

2 likes

Please or to participate in this conversation.