stevenc21's avatar

Type to Define Relationships Between People?

So I'm struggling with this.

I have a table of people.

I want to show the relationship between two people somehow. Obviously you can have more than one relationship per person.

How would you do a relationship between two people in a table of people? I was going to go with HasManyThrough, but then I was confused how you could do that with two people IDs.

I think for simplification, I'm fine with with a single relationship like "mother/daughter" for both people as the link, I don't care which is the mother and which is the daughter.

I figure this is the easiest way, since some relationships the inverse is different like, mother/daughter, and others like "siblings" the inverse is the same either way. But I guess I'd be open to doing it so that you know which is the mother and which is the daughter if it's simpler.

0 likes
4 replies
LaryAI's avatar
Level 58

One possible solution would be to create a pivot table called "relationships" that has three columns: "person1_id", "person2_id", and "relationship_type". The "person1_id" and "person2_id" columns would reference the "id" column in the "people" table, and the "relationship_type" column would store the type of relationship between the two people (e.g. "mother/daughter", "siblings", etc.).

To define the relationship in Laravel, you could use a many-to-many relationship with a custom pivot table. In your "Person" model, you would define the relationship like this:

public function relationships()
{
    return $this->belongsToMany(Person::class, 'relationships', 'person1_id', 'person2_id')
                ->withPivot('relationship_type');
}

This would allow you to retrieve all the relationships for a given person like this:

$person = Person::find(1);
$relationships = $person->relationships;

And you could also retrieve all the people who are related to a given person like this:

$person = Person::find(1);
$relatedPeople = $person->relationships()->where('person1_id', '<>', $person->id)->get();

This would give you all the people who are related to the given person, but not the person themselves.

Of course, you would need to create the necessary database migrations to create the "relationships" table and add the foreign key constraints.

stevenc21's avatar

I've really tried to figure this out, but I can't.

I'm trying to add a new relation, and I'm either getting no error and it's not adding or I'm getting an error. My latest method of trying was this:

public function addRelationship(){

        $newRelation = new Relationship;

        $newRelation->contact_id = 1;

        $newRelation->contact_id2 = 2;

        $newRelation->relationship_type_id = 1;



        $this->contact->relationships()->attach($newRelation);



        //$this->contact->relationships()->attach($this->selected_relationship_type, ['contact_id' => 1, 'contact_id' => 2]);

    }

Returns this error:

Illuminate \  Database  \  QueryException PHP 8.2.4 9.51.0 SQLSTATE[HY000]: General error: 1 no such table: main.relationship_types INSERT INTO "relationship" ("contact_id", "contact_id2") VALUES (1, ?)

I've tried other ways of attaching that didn't work either.

My files

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('relationship', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
            $table->foreignId('contact_id')
                ->references('id')->on('contacts')
                ->onDelete('cascade');
            $table->foreignId('contact_id2')
                ->references('id')->on('contacts')
                ->onDelete('cascade');
            $table->foreignId('relationship_type_id')
                ->references('id')->on('relationship_types');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('relationship');
    }
};
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Contact extends Model
{
    use HasFactory;

    protected $guarded = [];

    public function addresses()
    {
        return $this->hasMany(Address::class);
    }

    public function phones()
    {
        return $this->hasMany(Phone::class);
    }

    public function emails()
    {
        return $this->hasMany(Email::class);
    }

 

    public function relationships()
    {
        return $this->belongsToMany(Contact::class, 'relationship', "contact_id", "contact_id2")
                    ->withPivot('relationship_type_id');
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Relationship_Type extends Model
{
    use HasFactory;

    public function relationship(): BelongsToMany
    {
        return $this->belongsToMany(Relationship::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Relationship extends Model
{
    use HasFactory;


    public function contacts()
    {
        return $this->belongsToMany(Contact::class, "relationship")->withPivot('relationship_type_id');
    }
}
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('relationship__types', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
            $table->string("label")->default("");
            $table->string("description")->default("")->nullable;
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('relationship__types');
    }
};
jlrdw's avatar

Lookup nested sets. Or do self relations on table.

FYI Pedigree and descendant type relations have been covered exhaustively here is some past post.

Please or to participate in this conversation.