I am trying to create a category hierarchy using nested sets in Propel. I don't particularly care about the left/right stuff, I just want to be able to define a hierarchy.
I am having problems with propel complaining that a root node already exists with the given scope even though I am looking for an existing root node? I'm new to Propel and the nested set model so I'm really not sure what I'm doing wrong.
My table schema:
<table name="category">
<column name="id" type="integer" primaryKey="true" autoIncrement="true"/>
<column name="name" type="varchar" size="250" required="true" primaryString="true"/>
<behavior name="nested_set">
<parameter name="use_scope" value="true"/>
<parameter name="scope_column" value="scope"/>
<parameter name="left_column" value="left" />
<parameter name="right_column" value="right"/>
<parameter name="level_column" value="level"/>
</behavior>
<foreign-key foreignTable="category" onDelete="CASCADE" onUpdate="CASCADE">
<reference local="scope" foreign="id"/>
</foreign-key>
</table>
The function for creating the categories:
/**
* Takes an array of category names. The first name is taken as
* the root category and then each name is a child of the preceding
* name.
*/
function createCategories(array $names) {
$categories = [];
$root = CategoryQuery::create()
->filterByName($names[0])
->filterByLevel(0)
->findOneOrCreate();
if($root->isNew()) {
$root->save();
$root->setScopeValue($root->getId());
}
$categories[0] = $root;
foreach($names as $level => $name) {
if($level == 0) {
continue;
}
$category = CategoryQuery::create()
->filterByName($name)
->filterByScope($root->getScopeValue())
->findOneOrCreate();
if($category->isNew()) {
$category->insertAsFirstChildOf($categories[$level - 1]);
}
$categories[$level] = $category;
}
return $categories;
}
The issue was with the definition of a root node. I assumed that a root node was defined as one where the level is 0. Looking at the generated code it in fact defines a root as one where it's left value is 1.
To correctly have the node defined as a root you can call:
This error then goes away.