I’m creating resources or updating existing ones by importing a csv with their data through FormIt and a custom hook. I use tagger to create categories for those resources. Now my question is: How can I assign/update tagger categories from my csv data to a resource?
I have a row, which contains the categories to be assigned:
$row['category'] = 'Cat1, Cat2, Cat3'
Assume the resource object (either newly created or an already existing one selected) is available as $resource.
If possible, it would be nice to check if a category exists already in tagger or if it has to be created. If that’s too much, all categories that might occur in $row can also be created beforehand through the manager. So that’s not my main concern.
So i’ve been trying to wrap my head around this all day and this is what I came up if. Honestly I was too afraid to actually test it altogether yet (just tested parts of it), as I didn’t want to delete stuff that shouldn’t be deleted.
Also still learning a lot about xpdo and the first thing I’m confused with is:
When do I use $modx-> and when $xpdo->? Or does this not make a difference? I had the occurance while testing in a snippet, that I got an error saying “xpdo is not available” of some sort.
Here is what I have so far, I would highly appreciate any advice on making it work in general and also later improving performance as this is part of an import script which will be executed probably multiple thousand times.
$categories = array('test1','test2','test3'); // can be this or array('');
$resourceId = 25;
// check if any categories are given
if (!in_array('', $categories, true)) {
// clear existing tags
$resourceTags = $xpdo->getCollection('TaggerTagResource', ['resource' => $resourceId]);
foreach ($resourceTags as $resourceTag) {
$resourceTag->remove();
}
// assign tags
foreach ($categories as $cat) {
$c = $modx->query("SELECT id FROM modx_tagger_tags WHERE alias='$cat'");
if (is_object($c)) {
$catId = $c->fetch(PDO::FETCH_ASSOC);
$tagResource = $xpdo->newObject('TaggerTagResource',array(
'tag' => $catId,
'resource' => $resourceID,
));
}
}
} else {
// just clear tags
// is this also a valid way to do this?
$resourceTags = $xpdo->removeCollection('TaggerTagResource', ['resource' => $resourceId]);
}
(You could theoretically use xPDO independently from MODX and create your own object of the xPDO class. I think that is why $xpdo is sometimes used in the documentation.)
Make sure your variable names are always exactly the same. First you use $resourceId = 25; with a lower case d, then later with an upper case D ('resource' => $resourceID,). That doesn’t work.
$catId = $c->fetch(PDO::FETCH_ASSOC); $catId is not the ID here. It’s an associative array with a key “id”. $catId["id"] gives you the ID.
You can’t create the “TaggerTagResource” like this.
Thank you, this helped a lot! I think I have one issue left, at the part where I try to figure out, if the given category actually exists:
foreach ($categories as $cat) {
$c = $modx->query("SELECT id FROM mx_tagger_tags WHERE alias='$cat'");
if (is_object($c)) {
$catArr = $c->fetch(PDO::FETCH_ASSOC);
$catId = $catArr['id'];
//...
I thought I could check if the query $c returns anything by checking is_object($c) but if I understand correctly, then $c always returns an object, just an empty one if the query is empty?
When I check for the size of the result like mentioned here, my script breaks but I get no errors in the log:
if (!is_object($c)) {
return false;
}
if (count($c) > 0) {
$catArr = $c->fetch(PDO::FETCH_ASSOC);
$catId = $catArr['id'];
//...
I’m not so sure about this check. If you have an array with a lot of elements and one of them is empty ($categories = array('','test2','test3', ..., 'test100');), the code won’t add any tags.
Removing all the tags and then adding them again is not efficient (but easier to implement).
If the same resources with the same tags get updated again and again, a different approach is better.
Query all the existing tags of the resource and put them in an array.
For each tag in the update, check if it already exists in the array.
If it exists, delete it from the array.
If it doesn’t exist, add it to the database.
Delete the tags from the database that remain in the array.
That is what happens when you save a resource in the manager on the OnDocFormSave event.
If you don’t have that many tags and you update a lot of resources in a row, it will be faster if you load all the tags first and save them to an array, than making a new database query for every tag ($tag= $modx->getObject('TaggerTag',['alias' => $cat]);).
In general for a better performance, you want to avoid (unnecessary) database queries.