yiic shell doesn't make the relations() as should do

Hello, this happes when you use compounds names as table names.

Lets say that we have two tables:

Table 1:

Name: Single

Fields: id (PK), someField, someOtherField.

Table2:

Name: CompoundName

Fields: id(PK), idSingle(FK), aField, anotherField

And in mysql I declare a relation bewteen Single and COmpoundName (CompoundName.idSingle -> Single.id)

Well, having this: I do in yiic shell:

model CompoundName

this makes a model called CompoundName (both the file and the class)

and then i do:

model Single

this makes a model named Single. (Both the file and the class)

BUT in the relations() method of single, the following is automatically done by yiic:

return array(

        'compoundnames' => array(self::HAS_MANY, '[b]C[/b]ompoundname', 'idSingle'),


    );

Note that the model name is incorrect!!!

I’m using last svn yii 1.1. Mysql and winXP

Nobody have this issue?

HEY!!! nobody?

Note that if this is done this way, the latter when we do something like this:

$cn = $single->compoundnames;

The application will say taht the class Compoundname doesn’t exists!! (Of course Compoundname doesn’t exists!, the one that exists is CompoundName)

Again, note the caps!!!

Seem that this is not important. Nobody says a comment. I know that, may be, some other things are more important than this issue, but we are all here to make this framework better and better. I’m surprised because nobody answers me…

Hey PoL, I will check my Yiic generated code next Tuesday when I am back at work. It could be a windows thing. I work on a linux box so that will be an interesting thing to discover.

I am very new to Yii but I am sure that I can answer this question for you.

I spent a long time trying to figure out how to get models created in

/protected/backend/models/ instead of /protected/models/ but I figured it out and it works.

When I tried Yii on a windows machine many months ago I found the yiic tool a little strange (buggy)but it’s pretty slick on linux (I love linux for dev work)

I’ll keep you posted

doodle

Hi Pol

First of all over the weekend I was reading some of the Yii docs (yeah, get a life, I know!) and I came across this little nugget of wisdom here.

So probably camel case is not a good idea for database use. However I checked my Yiic generated code, and things are working for me the way that you expect them too.

Example




CREATE TABLE IF NOT EXISTS `WebPage` (

  `WebPageID` int(11) NOT NULL auto_increment,

...

.

...

 PRIMARY KEY  (`WebPageID`)

) ENGINE=InnoDB  DEFAULT CHARSET=latin1 ;


CREATE TABLE IF NOT EXISTS `Keyphrase` (

  `KeyphraseID` int(11) NOT NULL auto_increment,

  `KeyphrasePhrase` varchar(50) NOT NULL,

  PRIMARY KEY  (KeyphraseID)

) ENGINE=InnoDB  DEFAULT CHARSET=latin1  ;


CREATE TABLE IF NOT EXISTS `KeyphrasePage` (

  `KeyphrasePageID` int(11) NOT NULL auto_increment,

  `KeyphrasePageKeyphrase` int(11) NOT NULL,

  `KeyphrasePagePage` int(11) NOT NULL,

  INDEX(KeyphrasePageKeyphrase),

  FOREIGN KEY (KeyphrasePageKeyphrase) REFERENCES Keyphrase(KeyphraseID),

  INDEX(KeyphrasePagePage),

  FOREIGN KEY (KeyphrasePagePage) REFERENCES WebPage(WebPageID),

  PRIMARY KEY  (KeyphrasePageID)

) ENGINE=InnoDB  DEFAULT CHARSET=latin1 ;



Here is a snippet of Yiic generated code




	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(

			'keyphrasePages' => array(self::HAS_MANY, 'KeyphrasePage', 'KeyphrasePagePage'),

			'pagedatas' => array(self::HAS_MANY, 'Pagedata', 'PagedataPageID'),

		);

	}



in Yiic generated KeyphrasePage.php




class KeyphrasePage extends CActiveRecord

{

...

.

...

	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(

			'keyphrasePageKeyphrase' => array(self::BELONGS_TO, 'Keyphrase', 'KeyphrasePageKeyphrase'),

			'keyphrasePagePage' => array(self::BELONGS_TO, 'WebPage', 'KeyphrasePagePage'),

		);

	}




So it’s probably a windoze thing.

doodle

This is because when creating Single, it generates the related model class name purely based on the table name rather than the existing model class name. You will need to manually fix this. If your table name is named as word1_word2, then you will get Word1Word2 automatically.

I was waiting for your answer!!!

So, naming tables with ‘_’ to separate words is a good practice? (In OOP, it is better the camel case notation)

No matter, if I need to fix it by myself ok… and if naming tables with ‘_’ to separate words is the way I must go, then ok…

Now I just want your opinion about naming tables and objects, etc…

Thanks!!!

Hi, guys,

I’ve a problem with auto-generated relations in the model class file. I’ve defined the relations in my tables, but there were no relations generated in the model file. So I’ve thought the table relations weren’t OK and made a test with the tables, got2doodle gave above (WebPage, Keyphrase, KeyphrasePage).

I need the model files to be in the module "admin", so I ran the commands like this:

model admin.models.WebPage WebPage

model admin.models.Keyphrase Keyphrase

model admin.models.KeyphrasePage KeyphrasePage

Currently I’m using the yii-1.0.10.r1472 release.

Do you have any idea what is the problem ?

Thanks,

Miro

@PoL: yes, use lower case and underscore to concatenate words in table names (e.g. order_item). This will avoid you troubles such as case-sensitivity of table names in different OS. You may also add some table name prefix to better categorize your tables in a database (e.g. tbl_order_item, com_log, com_session) where “com_” stands for tables that could be reused in other systems. As a side note, you may also consider using lower case and underscore combination when naming table columns, even though it doesn’t follow the camelcase naming convention when being used in AR.

@mirrorps: you need to declare foreign key constraints when creating the tables. Otherwise, yii won’t have the necessary knowledge to build relations.

Thanks Quiang, is alwais good to increase our knowledge about "best practices"!.

And I thanks to ‘got 2 doodle’ for their answers (that doesn’t help me in this case, but are good for future reference)

[b]

[/b]

Hi, @qiang

These are my db tables:




CREATE TABLE atproduct (                                                                             

             fid int(11) NOT NULL auto_increment,                                                               

             frcategory int(11) default NULL,                                                                   

             fcode varchar(63) NOT NULL default '',                                                             

             ftitle_bg varchar(255) NOT NULL default '',                                                        

             ftitle_en varchar(255) NOT NULL default '',                                                        

             fprice double NOT NULL default '0',                                                                

             fpricecorporate double NOT NULL default '0',                                                       

             fshortdescription_bg text,                                                                         

             flongdescription_en text,                                                                          

             factive int(5) default '1',                                                                        

             fdateadded varchar(25) default NULL,                                                               

             fdateupdated varchar(25) default NULL,                                                             

             PRIMARY KEY  (fid)                                                                                 

           ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC;

           

           

CREATE TABLE atproduct2size (                                                                 

                  frproduct int(11) NOT NULL,                                                                 

                  frsize int(11) NOT NULL,                                                                    

                  PRIMARY KEY  (frproduct,frsize),                                                          

                  KEY FK_atproduct2size (frsize),                                                           

                  CONSTRAINT atproduct2size_ibfk_1 FOREIGN KEY (frproduct) REFERENCES atproduct (fid),  

                  CONSTRAINT atproduct2size_ibfk_2 FOREIGN KEY (frsize) REFERENCES atsize (fid)         

                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

                

CREATE TABLE atsize (                                                               

          fid int(11) NOT NULL,                                                             

          fname varchar(5) default NULL,                                                    

          PRIMARY KEY  (fid)                                                                

        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;




I have the constraints for the table atproduct2size, but the relations aren’t generated with the command:

model admin.models.Product2size atproduct2size

Any idea what am I doing wrong ?

Regards,

Miro

@mirrorps

My post in this thread shows sql that did produce relations in the Yiic generated model.

Maybe it helps,

doodle

Thanks @got2doodle,

I’ve saw it earlier. I wanted to ask you, when you ran the shell command model for each table, you gave in your post, did the framework generated the relations for the all 3 model classes, or just for 2 of them?

Thanks again.

Regards,

Miro

The Yiic tool generated all three relations, I have since modified my table definitions to be all lower case.

This is sql code I used

(I have actually modified it again but that doesn’t affect this example)

These are the yiic relations

(I added the joinType, I still don’t have it all working so the example is incomplete)


	 // model is webpage

	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(

			'keyphrasepages' => array(self::HAS_MANY, 'Keyphrasepage', 'pageid','joinType' => 'INNER JOIN',),

			'pagedatas' => array(self::HAS_MANY, 'Pagedata', 'webpageid','joinType' => 'INNER JOIN'),

		);

	}




	 // model is keyphrase

	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(

			'keyphrasepages' => array(self::HAS_MANY, 'Keyphrasepage', 'keyphraseid'),

		);

	}




	 //model is keyphrasepage

	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(

			'keyphrase' => array(self::BELONGS_TO, 'Keyphrase', 'keyphraseid'),

			'page' => array(self::BELONGS_TO, 'Webpage', 'pageid'),

		);

	}



take care,

doodle

@got2doodle,

Thanks a lot.

Regards,

Miro

Just to let you know what changes I have made to make things ‘work’ ( I admit, I am still trying to grasp how this functions, so far it definitely is ‘magic’)

Modified my relations method in webpage model as shown


	 // model is webpage

	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(

			'keyphrasepages' => array(self::HAS_MANY, 'keyphrasepage','pageid'),

			'pagedatas' => array(self::HAS_MANY, 'pagedata', 'webpageid'), 

		);

	}



note change of case for model names

in the controller


	public function loadwebpage($id=null)

	{

		if($this->_model===null)

		{

			if($id!==null || isset($_GET['id']))

// original code  // $this->_model=webpage::model()->findbyPk($id!==null ? $id : $_GET['id']); 

				$this->_model=webpage::model()->with('pagedatas')->findbyPk($id!==null ? $id : $_GET['id']);

			if($this->_model===null)

				throw new CHttpException(404,'The requested page does not exist.');

		}

		return $this->_model;

	}



In the view I can echo the data field from the pagedata table like this


<?php

foreach( $model->pagedatas as $pagedata)

{

echo $pagedata->data;

}

?>

Some things are starting to make sense with some help from others on this forum

doodle :)

If you want camelcase table names in windows when using MySQL you just have to modify your \mysql\bin\my.ini and in [mysqld] part add


lower_case_table_names = 2

I might as well continue this thread since there is relevant info here.

I am starting a project with a complex (for me) relational database, I want to generate the models and crud skeleton with the yiic tool. Here is an example of three tables that relate.


-- a table for different credit card types

CREATE TABLE IF NOT EXISTS `card_type` (

  `id` int(11) NOT NULL auto_increment,

  `name` varchar(50) NOT NULL,

  PRIMARY KEY  (id)

) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin  ;


-- a table for participant info

CREATE TABLE IF NOT EXISTS `participant` (

  `id` int(11) NOT NULL auto_increment,

...

...

...

  PRIMARY KEY  (id)

) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin ;


-- a table for unique credit card info

CREATE TABLE IF NOT EXISTS `participant_credit_card` (

  `id` int(11) NOT NULL auto_increment,

  `participant_id` int(11) default NULL,

  `card_type_id` int(11) default NULL,

  `card_number` varchar(50),

  `card_expiry` date NOT NULL default '0000-00-00',

  FOREIGN KEY (participant_id) REFERENCES participant(id),

  FOREIGN KEY (card_type_id) REFERENCES card_type(id),   

  PRIMARY KEY  (id)

) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin ;



Using yiic tool I generate a model for participant like this

>>model participant

this creates the file participant.php under protected/models/

here is the relations part of that file


	/**

	 * @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(

			'donations' => array(self::HAS_MANY, 'Donation', 'participant_id'),

			'event_participants' => array(self::HAS_MANY, 'EventParticipant', 'participant_id'),

			'events' => array(self::HAS_MANY, 'Events', 'contact_id'),

			'gender' => array(self::BELONGS_TO, 'Gender', 'gender_id'),

			'participant_credit_cards' => array(self::HAS_MANY, 'ParticipantCreditCard', 'participant_id'),

			'participant_food_healths' => array(self::HAS_MANY, 'ParticipantFoodHealth', 'participant_id'),

			'participant_participant_levels' => array(self::HAS_MANY, 'ParticipantParticipantLevel', 'participant_id'),

			'participant_programs' => array(self::HAS_MANY, 'ParticipantProgram', 'participant_id'),

		);

	}




the relevant part of my question is in this line


'participant_credit_cards' => array(self::HAS_MANY, 'ParticipantCreditCard', 'participant_id'),

notice participant_credit_card is now ‘ParticipantCreditCard’ this is expected based on discussion previously in this thread.

creating the model for participant_credit_card (table name) in yiic I type

>>model participant_credit_card

this creates the file participant_credit_card.php under /protected/models

the class created in this file is class participant_credit_card


class participant_credit_card extends CActiveRecord

{

	/**

	 * The followings are the available columns in table 'participant_credit_card':

	 * @var integer $id

	 * @var integer $participant_id

	 * @var integer $card_type_id

	 * @var string $card_number

	 * @var string $card_expiry

	 */



do I have to change the class name to particpantCreditCard ? and/or the model filename?

I know the naming conventions are important but I am confused a class named participant_credit_card it seems to me that it should be changed to particpantCreditCard and ParticipantCreditCard.php

any advice would be much appreciated

doodle