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

Uhanalainen's avatar

How to make relations

So, I've been trying to wrap my head around many-to-many relations. I think I've setup the database correctly and have the tables the way they should. As of now, saving works, but no relations are added, so my pivot tables are empty.

Here's a picture of my database structure.

http://i.imgur.com/2dx3j26.jpg

I'm using Laravels' built-in user auth system, obviously I've left the password table off of that pic because it's not relevant. What's important is to note that almost all relations here are many-to-many. An artist can have multiple records, and a record can have multiple, aka various Artist(s). Same for format (CD, LP or Digital). A user can make multiple "purchases", which also serves as his/her collection. Any registered user can add artists or records to the database, and then mark it purchased.

Why like this? Because, if the records were separate for each users I'd have 100 entries of the same album.

Anyway, here's some code, and what I need help with.

First, models.

Artist.php

    protected $table = 'artists';

    protected $fillable = [ 'name',  'country ];

    public function records()
    {
        return $this->belongsToMany('Record');
    }

Record.php

    protected $table = 'records';

    protected $fillable = ['title', 'year'];

    public function artist()
    {
        return $this->belongsToMany('Artist');
    }

    public function user()
    {
        return $this->belongsToMany('User');
    }

    public function formats()
    {
        return $this->belongsToMany('Format');
    }

Purchase.php

 protected $table = 'purchases';

    protected $fillable = [ 'price',  'bought_from ];

    public function user()
    {
        return $this->belongsTo('User');
    }

And here's record_user table

create_record_user_table.php

Schema::create('record_user', function(Blueprint $table)
        {
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('users');
            $table->integer('record_id')->unsigned();
            $table->foreign('record_id')->references('id')->on('records');
            $table->integer('purchase_id')->unsigned();
            $table->foreign('purchase_id')->references('id')->on('purchases');
            $table->timestamps();
        });

The other pivot tables work the same way (except for there being one less foreign key, of course). But I think my problem lies in the next piece of code.

I have a form for adding a new record. It has two dropdown menus, one for format and one for artist. Then plain text fields for everything else needed. I know I could probably use validator or something here, but this was just the easiest way to get it working. I figured once I get the adding working correctly I can tweak the rules later.

So what happens when I run it? Well, the record is added, and so is the purchase, but there's nothing in the pivot tables. I read up on pivot tables from three different sources, but couldn't get the hang of it. I would love to get some help with this.

I know this post is long and messy, but please, PLEASE help me with this. If there's any info missing or something, just ask and I shall deliver. Thanks in advance!

Here's the codes I tried using.

$record->artist()->save($artist);
$record->formats()->save($format);

RecordsController.php

public function confirm(PrepareRecordRequest $request)
    {
        $data = $request->all();
        $exists = Record::where('title',$data['title'])
            ->where('year', $data['year'])
            ->first();

        if ($exists)
        {
            flash()->error('Record already exists!');
            return Redirect('records/create')->withInput();
        } else {
           $record = Record::create(array('title' => Input::get('title'),
               'year' => Input::get('year')));
            $purchase = Purchase::create(array('price' => Input::get('price'),
                'bought_from' => Input::get('bought_from')));
            $artist = Input::get('artist');
            $format = Input::get('format');

            flash()->success('Record successfully added!');
            return Redirect()->action('PagesController@home');
        }
0 likes
8 replies
MThomas's avatar

Pleas try to add all your code in codeblocks (now accidentally part of it is in codeblocks due to the indentation). How? Add three backtics ` or tildes ~ on the line before and after your code.

And place one backtick ` before and after a string of inline code.

It is a bit hard to read now but probably you did not sync (scroll down to the Many To Many relations) the data onto the pivot tables

Uhanalainen's avatar

Thanks for the heads up, cleaned the OP up a little bit.

I thought maybe the problem lies in Record.php since it has 3 belongs-to-many relations.

This syncing. How would I use that?

Like so? Would this work?

$record->formats()->sync([$format]);
MThomas's avatar

No problem :)

I your case I guess you will have to attach the id :)

$record->formats()->attach($format->id);
Uhanalainen's avatar

That line gave me an error. PHPStorm says there's no attach method found in class.

MThomas's avatar

Does Laravel also give an error? Might be an PHPStorm problem :')

Uhanalainen's avatar

Laravel did give an error also.

But anyway, I've redone most of the app, simplified it a great lot just to get basic functionality working. Here's what I have at the moment:

index.php

        <ul>
            @foreach ($albums as $album)
                <li>{{ $album->name }}</li>
                @foreach ($album->artist as $artist)
                    <li>{{ $artist->name }}</li>
                @endforeach
            @endforeach
        </ul>

AlbumsController.php

public function handleCreate()
    {
        $purchase = new Purchase;
        $purchase->price = Input::get('price');
        $purchase->purchased_from = Input::get('purchased_from');
        $purchase->save();

        $album = new Album;
        $album->name = Input::get('title');
        $album->artist_id = Input::get('artist');
        $album->format_id = Input::get('format');
        $album->purchase_id = Input::get('purchased_from');
        $album->save();
}

Albums-table schema:

        Schema::create('albums', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('name');
            $table->integer('format_id')->unsigned();
            $table->foreign('format_id')->references('id')->on('formats');
            $table->integer('purchase_id')->unsigned();
            $table->foreign('purchase_id')->references('id')->on('purchases');
            $table->integer('artist_id')->unsigned();
            $table->foreign('artist_id')->references('id')->on('artists');
            $table->timestamps();
        });
    }

Album model

    protected $fillable = [
        'name'
    ];

    public function artist()
    {
        return $this->belongsTo('Artist');
    }

    public function format()
    {
        return $this->belongsTo('Format');
    }

    public function purchase()
    {
        return $this->belongsTo('Purchase');
    }

Now, when I try to view the index page, it says "Class 'Artist' not found", why?

MThomas's avatar
MThomas
Best Answer
Level 35

I Assume you are using L5? In that case the models are namespaced, so you will need the full class path: \App\Artist or import it at the top.

Uhanalainen's avatar

@MThomas I figured it out myself yesterday, but thanks for the answer, that would have solved the problem I had, now everything is working just as it should and I can go on and do the validation logics :)

Please or to participate in this conversation.