Finally I have discovered how to do this satisfactorily.
My requirement is to be able to create some tags - for example when installing xbCulture Components or when converting xbRefs Text References to Tag References in xbRefMan. These tags need to have a description and parent set as well as just a title so the simple function in TagsHelper::createTagsFromField(array())
does not cut the mustard. It only lets you create simple tags with just a title, and has a weird syntax whereby the title string has to be prefixed with #new#
The answer is to get a tags table object and use the bind()
, check()
and store()
table functions. In addition to get the parent_id set correctly you have to call the setLocation()
function before store() - this will set up the lft, rgt, and level fields but not the path field. To do that you have to rebuildPath($id)
with the new tag id after store().
So putting it all together with some error checking and detecting if a tag with the same alias already exists in a Component Helper function to which I can pass the data for the new tag as an array I get this:
public static function createTag(array $tagdata) {
Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_tags/tables');
$app = Factory::getApplication();
//check if alias already exists (dupe id)
$alias = $tagdata['title'];
$alias = ApplicationHelper::stringURLSafe($alias);
if (trim(str_replace('-', '', $alias)) == '') {
$alias = Factory::getDate()->format('Y-m-d-H-i-s');
}
$db = Factory::getDBO();
$query = $db->getQuery(true);
$query->select('id')->from($db->quoteName('#__tags'))->where($db->quoteName('alias').' = '.$db->quote($alias));
$db->setQuery($query);
$id = $db->loadResult();
if ($id>0) {
$app->enqueueMessage('Tag with alias '.$alias.' already exists with id '.$id,'Warning');
return $id;
}
$table = Table::getInstance('Tag', 'TagsTable', array());
// Bind data
if (!$table->bind($tagdata)) {
$app->enqueueMessage($table->getError(),'Error');
return false;
}
// Check the data.
if (!$table->check()) {
$app->enqueueMessage($table->getError(),'Error');
return false;
}
// set the parent details
$table->setLocation($tagdata['parent_id'], 'last-child'); //no error reporting from this one
// Store the data.
if (!$table->store()){
$app->enqueueMessage($table->getError(),'Error');
return false;
}
if (!$table->rebuildPath($table->id)) {
$app->enqueueMessage($table->getError(),'Error');
return false;
}
$app->enqueueMessage('New tag '.$tagdata['title'].' created with id '.$table->id);
return $table->id;
}
The data array is an assoc array and must include 'title', 'parent_id' (=1 if no parent) and 'published' (=1 for published as usual). 'description' is optional, as are all the other fields like publilication data will get set automatically if needed.
It seems to work ok.