Laravel – making many-to-many relationships easy

It’s times like this that I want to kiss +Taylor Otwell (and +Shawn McCool for his form-base-model bundle).

$interests = RegistrationForm::get('interests');
$user->interests()->sync($interests);

How beautifully simple and yet it hides such wonderful functionality.

What’s going on?

I’m building a registration form where users can select multiple checkboxes to indicate their interest in multiple items.

This requires a few tables and some incredibly simple models.

The Interests table migration

class Create_Interests_Table {

	public function up()
    {
		Schema::create('interests', function($table) {
			$table->increments('id')->unsigned();
			$table->integer('category_id')->unsigned();
			$table->string('name');
			$table->string('slug')->unique();
		});
	}
}

We can ignore the category_id here as I’m using it for something else, the other columns are nice and simple though. We have our incrementing id, the name of our interest, and a slug for the interest (which is going to be used later on for SEO friendly filtering URLs).

The Interest_user table migration

class Create_Interest_User_Table {

	public function up()
    {
		Schema::create('interest_user', function($table) {
			$table->increments('id')->unsigned();
			$table->integer('user_id')->unsigned();
			$table->integer('interest_id')->unsigned();
			$table->timestamps();
		});
	}
}

This is all pretty straight forward as well. An id, and then the relational user_id and interest_id.

The user model

This is a small excerpt of my User model.

public function interests()
{
	return $this->has_many_and_belongs_to('Interest');
}

Yes, it’s that beautiful.

My form (a little excerpt)

I can build the checkboxes nice and easily with:

foreach ($interest_category['interests'] as $interest_id => $interest_name) {
	echo Form::checkbox('interests[]', $interest_id, in_array($interest_id, (array) RegistrationForm::old('interests'))) . ' ' . __('interests.' . $interest_id);
}

There is a little bit of other stuff going on before this, but ultimately I’m grabbing an array of interests from the database and feeding them out to checkboxes. I still have to arrange the label, but I’m just testing this out at the moment. I’m building a multilingual site so I’m having to do some interesting things to ensure correctly localised labels are returned.

The registration controller

So I have my users table, my interests table and my interest_user table. The user has been created with:

// Save the User
$user = new User($user_data);
$user->save();

So I now have a user object and I can so easily sync the interests to the user and Laravel takes care of the rest. It populates the relational table with the user id and each interest id.

// Save the interests
$interests = RegistrationForm::get('interests');
$user->interests()->sync($interests);

Isn’t that just fantastic! If you’d like more information on building many-to-many relationships in Laravel check out the official documentation. What’s that RegistrationForm class? Check out the form-base-model bundle on github.

Comments