Last Updated: February 25, 2016
·
2.804K
· amsross

Create Many-to-Many Association with Idiorm/Paris

As simple as this really turned out to be, I struggled with this a bit as it isn't explicitly discussed in the docs (http://paris.readthedocs.org/en/latest/associations.html#has-many-through).

The idea is that you have two Models with a has_many_through relationship and an intermediate Model to manage that relationship.

A little DB magic to get things hooked up:

CREATE TABLE IF NOT EXISTS `Addresses` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `Users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

CREATE TABLE IF NOT EXISTS `AddressUser` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `Addresses_id` int(11) NOT NULL,
  `Users_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id` (`id`),
  KEY `Addresses_id` (`Addresses_id`),
  KEY `Users_id` (`Users_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

ALTER TABLE `AddressUser`
  ADD CONSTRAINT `AddressUser_ibfk_3` FOREIGN KEY (`Users_id`) REFERENCES `Users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `AddressUser_ibfk_4` FOREIGN KEY (`Addresses_id`) REFERENCES `Addresses` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

The main models:

// One side of the relationship
class User extends \Model {
    public static $_table = 'Users';
    public function addresses() {
        return $this->has_many_through('Address');
    }
}

// Another side of the relationship
class Address extends \Model {
    public static $_table = 'Addresses';
    public function users() {
        return $this->has_many_through('User');
    }
}

// Intermediate model for managing the relationship
class AddressUser extends \Model {
    public static $_table = 'AddressUser';
}

Then to create an association or link two of the main Models together:

$address_user = \Model::factory('AddressUser')->create();
$address = \Model::factory('Address')->find_one($address_id);
$user = \Model::factory('User')->find_one($user_id);

// Just to make sure these entities actually exist in the db
if ($address && $user) {
    $address_user->addresses_id = $address->id;
    $address_user->users_id = $user->id;
    $address_user->save();
}

At this point you should be able to create new rows in the AddressUser table that link up with the correct models in the respective Addresses and Users tables.

3 Responses
Add your response

Matt, this is great!

It's really helped me out and got me through a problem I didn't know how to solve.

I suspect one could override the save() method of both User and Address to ensure a valid UserAddress is saved for each relationship as well.

You're right too, this should be included in the documentation :)

over 1 year ago ·

I am sure it is just because I am too close to the project, but I can't really see what is missing from the docs here so please could you report this explicitly as an issue or better yet a pull request on the project so that the documentation can be improved.

over 1 year ago ·

What about delete the relationship between the user and their addresses? How you do it?

over 1 year ago ·