Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

fluentd's avatar

Adding foreign key to relationship model

Not sure if the title makes any sense but here is my question. I currently have a Family model and a Contact model. Once the Family is created I am trying to add contacts to the Family. The part that I am getting confused it how to tell the contact form that this new contact I am creating is related to a specific id in the Family model.

Currently I have a "Main" form that lets me insert family and contact data at once but I want the ability to add additional contacts to the model.

My routes are setup like the following:

Route::resource('families', 'FamiliesController');
Route::resource('families.contacts', 'ContactsController');

The form is currently at

/families/{id}/contacts/create/

My Models are setup like:

Family Model

public function contacts()
{
    return $this->hasMany('App\Contact');
}

Contact Model

public function family()
{
    return $this->belongsTo('App\Family');
}

I currently have the create route setup with the contact form being displayed, but once I submit the form I get a QueryException Error

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`billing_dev`.`contacts`, CONSTRAINT `contacts_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`) ON DELETE CASCADE) (SQL: insert into `contacts` (`first_name`, `middle_name`, `last_name`, `relationship`, `address1`, `address2`, `city`, `state`, `zip`, `cell_phone`, `home_phone`, `work_phone`, `email`, `is_primary`, `updated_at`, `created_at`) values

I tried setting the family_id manually just to see if I could get it to work by adding the following to the store method:

$contact['family_id'] = 1;

but the idea failed me.

How do I go about grabbing the id which is in the URL "/families/1/contacts/create/" and assign that to the family_id field on the contacts Model.

I may be going about this the wrong way as I am still trying to learn Laravel.

0 likes
20 replies
fluentd's avatar
public function store(ContactRequest $request)
{
    $contact = Contact::create($request->all());
    $contact['family_id'] = 1;

    return $contact;

//  return redirect('families/{id}'); // would like to redirect to the family that I am adding a contact too.
}
michaeldyrynda's avatar

Show us the migration for your Contact model - I suspect it's trying to insert null for family_id because it hasn't been told which Family to attach to.

If this is the case, you'll need to make your family_id nullable with a default of null - which is generally good practice with integer foreign key constraints.

As for your question about grabbing the family id from the request, update your store method:

public function store($family_id, ContactRequest $request)
{
    $contact = Contact::create($request->all() + [ 'family_id' => $family_id, ]);

    return $contact;

    //  return redirect('families/' . $family_id);
}

Better way, this way you validate that the family you're creating a contact for exists. Catch the ModelNotFoundException and redirect as appropriate. Replace findOrFail with a find if you've validated the $family_id elsewhere:

public function store($family_id, ContactRequest $request)
{
    $family = Family::findOrFail($family_id);
    $contact = $family->contacts()->create($request->all());

    return $contact;

    //  return redirect('families/' . $family_id);
}
fluentd's avatar

@deringer here is my contact migration

public function up()
{
    Schema::create('contacts', function(Blueprint $table)
    {
        $table->increments('id');
        $table->integer('family_id')->unsigned();
        $table->string('first_name', '25');
        $table->string('middle_name', '25');
        $table->string('last_name', '25');
        $table->string('relationship', '15');
        $table->string('address1', '40');
        $table->string('address2', '40');
        $table->string('city', '25');
        $table->string('state', '25');
        $table->string('zip', '10');
        $table->string('cell_phone', '20');
        $table->string('home_phone', '20');
        $table->string('work_phone', '20');
        $table->string('email', '50');
        $table->enum('is_primary', array('1', '0'));
        $table->timestamps();

        
        /**
         * Creates a relationship between contacts and families tables. 
         * This also references the ID field in the families table. 
         * onDelete will make it so once the families ID is 
         * deleted it will cascade down and delete the
         * relationship contact.
         */

        $table->foreign('family_id')
            ->references('id')
            ->on('families')
            ->onDelete('cascade');
    });
}
michaeldyrynda's avatar

Ok @fluentd - as I suggested, just make the family_id field nullable:

// ...
    $table->integer('family_id')->unsigned()->nullable()->default(null);
//...

That'll solve the integrity constraint issue you're encountering it. My previous post should help you address actually assigning the contact to the Family model and then redirecting.

Depending on how much data you have and whether or not rolling back is an option, you could just create an alter migration along the lines of:

Schema::table('contacts', function (Blueprint $table)
{
    $table->integer('family_id')->unsigned()->nullable()->default(null)->change();
});
RomainLanz's avatar

Hey @fluentd

You are using nested resources here. The best way to store your Contact model is to do that:

// Note that I'm using Model Binding.
public function store(Family $family, ContactRequest $request)
{
    $family->contacts()->create($request->all());

    return redirect()->route('families.contacts.index', [$family->id]);
}
fluentd's avatar

@deringer I am looking for your suggested store method and I am trying to figure it out.

public function store($family_id, ContactRequest $request)
{
    $family = Family::findOrFail($family_id);
    $contact = $family->contacts()->create($request->all());

    return $contact;

    //  return redirect('families/' . $family_id);
}

I am not seeing where it gets the Family model's id field and assigns it to the family_id field on the newly created contact. Could you break it down for me? I am specially interested in what this part is doing? "store($family_id" Does the laravel documentation explain this?

michaeldyrynda's avatar

@fluentd you said your form was at the following route:

/families/{id}/contacts/create/

Laravel will automagically take route parameters ({id}) and pass them into your closure or controller method. The variable name in the method signature doesn't have to match the route parameter name exactly.

As for the family_id being assigned in the model, that's handled by the relationship you have defined for the Family model - that is the contacts method in the model.

You could also do something like this, keeping in mind you'll have to make the family_id field in the database nullable first.

$contact = Contact::create($request->all());
$family = Family::findOrFail($family_id);
$family->contacts()->save($contact);
fluentd's avatar

@deringer So adding store($family_id, Laravel already knows that I want to assign the /families/4/contacts/create/ , for example "4" as the family_id in the contact table?

michaeldyrynda's avatar

That's right - Laravel will automatically inject your route parameters into your controller methods.

jimmck's avatar

Hi, May I make a humble suggestion. i have been working SQL and databases and code API's for many years. It would be helpful to show your table schemas in SQL not Eloquent. Show your queries in SQL not Eloquent. Your SQL may be fine but the API may not translate into the correct SQL. Also make the database engine do the heavy lifting. Simulating joins is inefficient and will lead to problems. I am saying that is not being done here. I saw a case where a developer wrote beautiful XQuery logic to join XML result sets. It worked fine in dev and blew up in test. Had the developer simply wrote the correct join logic the database would return a result that could be parsed into the desired XML structure. So a simple question is the Family table entry id of the child contact being inserted in the family table? That will cause the constraint violation.

fluentd's avatar

@deringer Out of curiosity how would you go about taking in two route parameters? Such as:

families/{families}/contacts/{contacts}/edit
michaeldyrynda's avatar

Your method could look like this:

public function edit($family_id, $contact_id) {
    // ...
}
fluentd's avatar

@deringer So if my Family model only has an id field and my Contact model has an id field as well then I would use

public function edit($id, $id) {

}

How does Laravell know which is which?

michaeldyrynda's avatar

It passes them to you function in the order that they're defined in the route, it's up to you to name them sensibly.

fluentd's avatar

@deringer This still doesnt seem to be doing the trick. I migrated my database to include your suggestion:

$table->integer('family_id')->unsigned()->nullable()->default(null);

I'm still getting thrown the following:

QueryException in Connection.php line 614:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

as well as:

PDOException in Connection.php line 358:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`billing_dev`.`contacts`, CONSTRAINT `contacts_family_id_foreign` FOREIGN KEY (`family_id`) REFERENCES `families` (`id`) ON DELETE CASCADE)

I have a feeling that this error means that it is trying to add a value into the family_id field that is not available? Meaning its not pulling the correct ID from the URI to insert into the field.

michaeldyrynda's avatar

It means that you're trying to insert invalid data into the field.

What's your route look like, your controller method, and your model? Can you dump your controller method's arguments and see that they're being set?

fluentd's avatar

@deringer

Ya I thought that is what it was doing.

Here is the route:

Route::resource('families', 'FamiliesController');
Route::resource('families.contacts', 'ContactsController');

Here is the Store method

public function store($family_id, ContactRequest $request)
{
    $contact = Contact::create($request->all() + ['family_id' => $family_id]);

    return $contact;

    //  return redirect('families/' . $family_id);
}

Contact Model:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Contact extends Model {

protected $fillable = [
    'family_id',
    'first_name',
    'middle_name',
    'last_name',
    'relationship',
    'address1',
    'address2',
    'city',
    'state',
    'zip',
    'cell_phone',
    'home_phone',
    'work_phone',
    'email',
    'is_primary'
];

public function family()
{
    return $this->belongsTo('App\Family');
}

public function scopePrimary($query){
    return $query->where('is_primary', 1);
}
}

Family Model:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Family extends Model {

protected $fillable = [
    'family_name',
    'marketing',
    'health_insurance',
    'health_insurance_policy',
    'doctor_name',
    'doctor_phone'
];

public function memberships()
{
    return $this->hasMany('App\Membership');
}

public function contacts()
{
    return $this->hasMany('App\Contact');
}
}

How would I go about dumping my controller method's arguments? dd? Where would I put it?

Thanks for your time once again...

fluentd's avatar

I am noticing that the is being encoded when I submit the Create contact form.

families/%7Bid%7D/contacts/create

Its coming from my form open

{!! Form::open(['url' => '/families/{id}/contacts/create']) !!}

Looks like its encoding the {id} .. should I not be using the {id} in the form post url?

Please or to participate in this conversation.