I took an initial pass at this and the model generator properly generated relations. I then went to perform a complex query (via CDbCriteria) that relied on these relations. Because I wasn't defining a primary key on one of the tables, a call to CDataProvider::getData() wasn't working. First, here's my ddl:
CREATE OR REPLACE FUNCTION check_email(email text) RETURNS bool LANGUAGE plperlu AS $$ use Email::Address; my @addresses = Email::Address->parse($_[0]); return scalar(@addresses) > 0 ? 1 : 0; $$; DROP TABLE IF EXISTS ham_users CASCADE; CREATE TABLE ham_users( userid BIGSERIAL NOT NULL PRIMARY KEY ,email VARCHAR(128) NOT NULL UNIQUE ,username VARCHAR(64) NOT NULL UNIQUE ,CONSTRAINT proper_email CHECK(check_email(email)) ); DROP TABLE IF EXISTS ham_authentication; DROP TYPE IF EXISTS authentication_type; CREATE TYPE authentication_type AS ENUM('password','facebook'); CREATE TABLE ham_authentication( userid BIGINT NOT NULL REFERENCES ham_users(userid) ,type authentication_type NOT NULL ,data VARCHAR(128) ,PRIMARY KEY(userid,type) ); DROP TABLE IF EXISTS ham_user_attributes; CREATE TABLE ham_user_attributes( id BIGSERIAL NOT NULL PRIMARY KEY ,userid BIGINT NOT NULL REFERENCES ham_users(userid) ,key VARCHAR(128) NOT NULL ,value TEXT ); CREATE INDEX idx_ham_id_key ON ham_user_attributes(userid,key);
I originally didn't specify a primary key on the ham_user_attributes table. It may be significant that I originally called the "userid" column "id"; the ham_user_attributes table didn't have a primary key, only the separately-created index.
In the original ddl, the gii model generator properly defined authentication and userAttribute relations in models/User.php.
I'm new to gii; I don't think this is the correct way to perform this query, but it should work. I'm trying to perform authentication for the login form (in components/UserIdentity.php). So I need to select users with a specified username and get their (hashed) password from ham_authentication along with a salt from ham_user_attributes. Here's my flawed attempt from UserIdentity::authenticate():
$username = strtolower($this->username); $criteria = new CDbCriteria(); $criteria->with = array('userAttributes','authentications'); $criteria->addCondition('LOWER(username)=:username'); $criteria->addCondition('"userAttributes".key=:attribute_key'); $criteria->addCondition('"authentications".type=' .':authentication_type'); $criteria->params = array(':username' => $username ,':attribute_key' => self::SALT ,':authentication_type' => 'password'); $criteria->together = true; $provider = new CActiveDataProvider( 'Users',array('criteria' => $criteria) ); $data = $provider->getData();
I think the better way to do this would be to use User::model() to get a user with the specified username and then query the salt and password separately. Be that as it may, this didn't work because the ham_user_attributes table didn't have a primary key. The call to getData() resulted in a warning about using an undefined value somewhere deep in the innards of yii. So I refactored the ddl to rename the id column on the ham_users table to "userid" and added a primary key to ham_user_attributes.
When I say it's not generating relations, to be clear, here is that method from models/Users.php:
/** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( ); }
I may need to adjust it indeed. As I mentioned, I am specifying the table prefix as "ham_" in config/main.php. It was working in one iteration and then changes described resulted in the above. I've also tried the Giix Model Generator, but that had the same result.
This seems like a bug. Thanks -
-Matt