user3609683
user3609683

Reputation: 11

Models with relationships

I´m currently trying to use Phalcon for a backend service framework for apps. I know PHP quite well, and i've heard a lot good things about Phalcon and decided to give it a try. I like it very much, although i have stumbled across a problem i cannot seem to solve, not even by spending the last couple of hours on google (Normally that does the trick).

Anyways, i´m trying to define a relationship betwen two Models - A user table, and a country table. Each user has a country, but not the other way around. I started by simply defining a column in the user table as a foreign key to the country table. I used the hasOne method in the initializing method on the Users model, but this resulted in warning when doing a $user->country->name.

So i re-RTFM, reworked the tables and the model, added a relational table between the user and the country table. My current table design is (A little truncated - i left some non important fields out):

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2 ;

CREATE TABLE IF NOT EXISTS `countries` (
  `code` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE IF NOT EXISTS `users_countries` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `users_id` int(10) NOT NULL,
  `countries_id` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `countries_id` (`countries_id`),
  KEY `users_id` (`users_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=5 ;
ALTER TABLE `users_countries`
  ADD CONSTRAINT `users_countries_ibfk_4` FOREIGN KEY (`countries_id`) REFERENCES `countries` (`code`) ON DELETE CASCADE ON   UPDATE CASCADE,
  ADD CONSTRAINT `users_countries_ibfk_3` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

And my PHP Models:

class Users extends \Phalcon\Mvc\Model {
  // Properties here - all public.
  public function initialize() {}
    $this->hasOne('id', 'UserCountries', 'users_id', array('foreignKey' => TRUE));
    $this->hasOne('id', 'UserPictures', 'users_id');
  }
}

class UsersCountries extends \Phalcon\Mvc\Model {
  // Properties here - all public.
  public function initialize() {
    $this->belongsTo('users_id', 'Users', 'id');
    $this->belongsTo('countries_id', 'Countries', 'id');
  }
}

class Countries extends \Phalcon\Mvc\Model { }

So the idea is that the user know about the country, but the country doesn´t know anything about the user.

Now when i create a user, i do

$user = new Users;
$user->username = "kaa";
$user->password = "test";
$user->save();

The user gets created alright, but i do not have a clue about how to create the relation to country the proper way. I could do:

$country = new UsersCountries;
$country->users_id = $user->id;
$country->countries_id = 'DK';
$country->save();

which does store the relation in the DB, but i cant find any way to access the relation from the user object. When i try by

$user->usersCountries 

i get the exception "Uncaught exception 'Phalcon\Mvc\Model\Exception' with message 'Model 'UserCountries' could not be loaded".

So it seems to me, that im kinda missing the point of using these relationships between models in Phalcon. Anyone know how to work with these relationship s the right way / know a place i can read about them?

Upvotes: 1

Views: 8521

Answers (2)

jodator
jodator

Reputation: 2465

tl;dr: looks like typo

It looks like either you have typo in code, because error states that Phalcon can not find UserCountries not UsersCountries

So looking at your models, maybe it should be like this:

class Users extends \Phalcon\Mvc\Model {
 // Properties here - all public.
  public function initialize() {}
    // typos here?
    $this->hasOne(
        'id',
        'UsersCountries',
        'users_id',
        array('foreignKey' => TRUE)
    );
    $this->hasOne('id', 'UsersPictures', 'users_id');
  }
}

Since the 'UsersCountries' must be the name of the model and you have class UsersCountries not UserCountries.

By the way, you can set alias for model when defining relationship:

$this->hasOne('id', 'UsersCountries', 'users_id',
    array('foreignKey' => TRUE, 'alias' => 'UserFlag'));

So then you can call it like this:

$user = Users::findFirst();
$user->UserFlag->Countries;

Upvotes: 2

David Duncan
David Duncan

Reputation: 1858

You are using a many to many (n-n) relationship for users to countries in your database tables, and a 1-n relationship in your phalcon models when it sounds like you are wanting a one to many relationship.

In effect, you have made it so that a user can have any number of countries, and a country can have any number of users. As you stated above this is not what you were looking for. You want each user to have one country correct?

You can safely remove your users to countries table and models, and just create a column in your users table called country_id, that will store the PK of the country.

    class Users extends \Phalcon\Mvc\Model
    {
      public function initialize()
      {
          $this->hasOne('country_id', 'Countries', 'id', array(
              'alias' => 'country'
          ));
      }
    }

then in your code/controller all you need to do is find your country

$user = new User();

// if our countries table has a column named abbreviation, we can use phalcons magic find method to search by that columns name
$user->country = Countries::findFirstByAbbreviation('DK');

$user->create();

Upvotes: 1

Related Questions