Hierarchical Models

Hello, I have the following tables:




CREATE TABLE IF NOT EXISTS `topic` (

  `topic` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(255) DEFAULT NULL,

  `area_name` smallint(6) NOT NULL DEFAULT '0',

  PRIMARY KEY (`topic`)

)


CREATE TABLE IF NOT EXISTS `topic_link` (

  `parent` int(11) NOT NULL DEFAULT '0',

  `child` int(11) NOT NULL DEFAULT '0'

) 



Basically, one topic can have N children, which in turn, can have their own children. I’m a bit confused on how to create the relations in the respective models.

I’ve created the following Topic model:




class Topic extends CActiveRecord {

public function relations() {

	return array(

		'parent' => array(self::BELONGS_TO, 'TopicLink', 'parent'),

		'children' => array(self::HAS_MANY, 'TopicLink', 'child'),

	);

}

}



But have no idea on how to create the Topic_Link model.

Can anyone help? Thanks!

It looks like a MANY_MANY relation where you don’t need a model for the junction table. Remember to define a composite primary key holding both columns in the ‘topic_link’ table.

Also I would suggest a naming convention, where primary keys are always named ‘id’ and foreign keys are named ‘table_id’ where ‘table’ is a singular form of the referred table name. The FK may contain a prefix to suggest the relation meaning, like ‘parent_topic_id’.

Oh thanks, it helped, but I’m still not able to get the children of a specific topic.

This is what I did:




class Topic extends CActiveRecord {

public function relations() {

return array(

	'children' => array(self::MANY_MANY, 'TopicLink', 'topic_link(parent, child)'),

);

}

}


class TopicLink extends CActiveRecord{

public function primaryKey(){

	return array('parent', 'child');

}

public function relations() {

return array();

}

}



By doing so, when I iterate over the children of a topic, I get all the subsubtopics, not the immediate subtopics. For example,




$topics = Topic::model()->findAll("topic=1");

foreach ($topics as $topic) {

	echo $topic->topic.") ".$topic->name;

	$children = $topic->children;

	foreach ($children as $child) {

		echo "<br> -> ".$child->parent." - ".$child->child;

	}

	echo "<br>";

}



It brings me:




1) Root topic

-> 22 - 45

-> 22 - 46

-> 22 - 47

-> 22 - 48

-> 21 - 38

-> 21 - 39

-> 21 - 40

-> 21 - 41

-> 21 - 42

-> 21 - 43

-> 21 - 44

-> 20 - 36

-> 20 - 37

-> 19 - 32

-> 19 - 33

-> 19 - 34

-> 19 - 35

-> 18 - 25

-> 18 - 26

-> 18 - 27

-> 18 - 28

-> 18 - 29

-> 18 - 30

-> 18 - 31

-> 23 - 49

-> 23 - 50

-> 23 - 51

-> 23 - 52

-> 23 - 53

-> 23 - 54

-> 24 - 55

-> 24 - 56

-> 24 - 57

-> 24 - 58

-> 24 - 59

-> 24 - 60

-> 24 - 61

-> 24 - 62

-> 24 - 63



Where IDs from 18 to 24 are subtopics of 1.

And doing


$child->parent->name

does not work either.

For a MANY_MANY relation you don’t use a model for the junction table. The relation should look like:




'children' => array(self::MANY_MANY, 'Topic', 'topic_link(parent, child)'),

'parents' => array(self::MANY_MANY, 'Topic', 'topic_link(child, parent)'),



It worked like a charm :D Many thanks!