taxonomy_deploy.module in Deploy - Content Staging 6
Deployment API which enables modules to deploy items between servers.
This module manages deployment-related issues for taxonomy terms and vocabularies.
File
modules/taxonomy_deploy/taxonomy_deploy.moduleView source
<?php
/**
* @file
* Deployment API which enables modules to deploy items between servers.
*
* This module manages deployment-related issues for taxonomy terms and
* vocabularies.
*/
/**
* Implementation of hook_menu().
*/
function taxonomy_deploy_menu() {
$items = array();
$items['admin/content/taxonomy/deploy'] = array(
'title' => t('Deploy'),
'description' => t('Add a taxonomy vocabulary to a deployment plan.'),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'taxonomy_vocabulary_deploy_add_form',
5,
),
'access arguments' => array(
'add items to deployment plan',
),
'file' => 'taxonomy_deploy.pages.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Implementation of hook_node_deploy_check().
*
* This is the dependency checking hook for nodes, called when
* a deployment has been requested that includes a node.
*
* @param $node
* The node object being deployed
*/
function taxonomy_deploy_node_deploy_check($node) {
taxonomy_deploy_check_taxonomy($node->taxonomy);
}
/**
* Manage the dependencies for an array of taxonomy terms.
*
* @param $taxonomy
* Array of taxonomy terms, as is included with a node in node_load.
* You can also pass a single tid here, and the function will manually
* get the term and put it into an array of the appropriate format.
*/
function taxonomy_deploy_check_taxonomy($taxonomy) {
// If the param is not an array, assume it is a tid. Get the
// term and put it in an array such that the rest of the function
// can work as normal.
if (!is_array($taxonomy)) {
$term = taxonomy_get_term($taxonomy);
$taxonomy = array();
$taxonomy[] = $term;
}
// Retrieve the remote server information.
$url = variable_get('deploy_server_url', '');
$pid = variable_get('deploy_pid', 0);
// As we get vids from the remote server, cache them here for future
// use to reduce roundtrips.
//
// @todo
// Make this static so that it will maintain through the recursive function calls?
// Also, should probably cache the terms as well since its quite possible to be
// checking a single term multiple times because of use in parents / related terms.
$vocabularies = array();
// Every item in a node's taxonomy array is a term array.
foreach ($taxonomy as $term) {
// Convert to array if its not already
$term = (array) $term;
// We keep a unique list of all the vids we encounter, so we can
// handle them next. Terms must be handled before vocabularies in order
// to make sure that vocabularies always get deployed before their terms.
if (!in_array($term['vid'], $vocabularies)) {
$vocabularies[] = $term['vid'];
}
// If this term is already in the deployment plan then either
// a) it was added by the user and will get checked down the line or
// b) it was added through dependency checks and its already been
// dealt with. So we just move on in this case.
if (!deploy_item_is_in_plan($pid, 'taxonomy_term', $term['tid'])) {
// Does this term exist on the remote server?
$remote_key = deploy_get_remote_key(deploy_uuid_get_term_uuid($term['tid']), 'term_data');
// If not we're going to add it to the deployment plan, with a weight
// of min(weight) - 1.
if (!$remote_key) {
// Note that when adding a taxonomy term or vocabulary to a plan, we save 'taxonomy_term'
// or 'taxonomy_vocabulary' in the $module parameter, despite the fact that this is all
// coming from the 'taxonomy' module. It just makes sense since they are both dealt with
// completely differently, and it prevents me from doing some hackery like storing a
// serialized array in the $data field.
deploy_add_to_plan($pid, 'taxonomy_term', 'taxonomy term: ' . $term['name'], $term['tid'], deploy_get_min_weight($pid) - 1, DEPLOY_TAXONOMY_TERM_GROUP_WEIGHT);
// Having added this term to the plan, we now need to dependency check it
// term's parents. This will continue recursively until we get to a root term.
taxonomy_deploy_check_taxonomy(taxonomy_get_parents($term['tid']));
// And its related terms. Same deal.
taxonomy_deploy_check_taxonomy(taxonomy_get_related($term['tid']));
}
}
}
// Mow we need to do the same thing for the vocabularies.
foreach ($vocabularies as $vid) {
if (!deploy_item_is_in_plan($pid, 'taxonomy_vocabulary', $vid)) {
// Does this vocabulary exist on the remote server?
$remote_key = deploy_get_remote_key(deploy_uuid_get_vocabulary_uuid($vid), 'vocabulary');
// If not we're going to add it to the deployment plan, with a weight
// of min(weight) - 1.
if (!$remote_key) {
// I hate doing this load here but i have to bite the bullet so that the
// deployment listing makes sense.
$vocabulary = taxonomy_vocabulary_load($vid);
deploy_add_to_plan($pid, 'taxonomy_vocabulary', 'taxonomy vocabulary: ' . $vocabulary->name, $vid, deploy_get_min_weight($pid) - 1, DEPLOY_TAXONOMY_VOCABULARY_GROUP_WEIGHT);
}
}
}
}
/**
* Implementation of hook_deploy().
*
* @param $tid
* Unique identifier for the term we're deploying.
* @return
* The results of our deployment.
*
* For reference here is how the term needs to be formatted.
*
* [name] => Test
* [description] => test
* [parent] => Array (
* [247] => 247
* )
* [relations] => Array (
* [247] => 247
* [249] => 249
* )
* [synonyms] => test test
* [weight] => 5
* [vid] => 3
* [tid] => 335
*
*/
function taxonomy_term_deploy($tid) {
// If there is no term with this tid then bail
$term = taxonomy_get_term($tid);
if (!$term) {
return FALSE;
}
// Fill out term object with all the data it needs that taxonomy_get_term() doesn't provide
// because it sucks.
//
// Yes it really is "parent" even though a term can have multiple parents.
$term->parent = array();
foreach (taxonomy_get_parents($tid) as $key => $parent) {
// if the deployment weighting has done its job, then any parent terms
// should have been deployed prior to this one. If not, then we need to fail out
$remote_key = deploy_get_remote_key(deploy_uuid_get_term_uuid($key), 'term_data');
$term->parent[$remote_key['tid']] = $remote_key['tid'];
}
// Same thing for related terms.
$term->relations = array();
foreach (taxonomy_get_related($tid) as $key => $relation) {
// If you have circular related terms (which is possible) then one of them has
// to come up before the other one, which means the other one will not exist
// remotely. Therefore we can't really fail out when we encounter that situation,
// therefore when we enounter that situation we just ignore that term and move on.
// It all works out because when the related term comes up, it will link them
// both at save anyways.
$remote_key = deploy_get_remote_key(deploy_uuid_get_term_uuid($key), 'term_data');
$term->relations[$remote_key['tid']] = $remote_key['tid'];
}
// Synch up with the remote vocabulary, which in theory can't not exist at this point.
$remote_key = deploy_get_remote_key(deploy_uuid_get_vocabulary_uuid($term->vid), 'vocabulary');
$term->vid = $remote_key['vid'];
// Synonyms are much easier thankfully.
$term->synonyms = implode("\n", taxonomy_get_synonyms($tid));
// Mormally, like with users and nodes, the uuid is added to the object in the 'load'
// op of their hook. Taxonomy terms and vocabs have no load op, so we have to
// get it by hand.
$uuid = deploy_uuid_get_term_uuid($tid);
$remote_key = deploy_get_remote_key($uuid, 'term_data');
$term->tid = isset($remote_key['tid']) ? $remote_key['tid'] : NULL;
$term->uuid = $uuid;
return deploy_send(array(
'taxonomy.saveTerm',
), array(
$term,
));
}
/**
* Implementation of hook_deploy().
*
* @param $vid
* Unique identifier for the vocabulary we're deploying.
* @return
* The results of our remote call.
* @todo
* At dependency checking for associated content types to make sure
* they exist remotely and/or are added at push time through a call to
* hook_taxonomy_vocabulary_deploy_check().
*
* For reference here is a taxonomy vocabulary object.
*
* [name] => test
* [description] => test
* [help] => test
* [nodes] => Array (
* [booklist] => booklist
* [essay] => essay
* [letter] => letter
* )
* [tags] => 1
* [multiple] => 1
* [required] => 1
* [weight] => 4
* [hierarchy] => 0
* [relations] => 1
* [vid] => 5
*
*/
function taxonomy_vocabulary_deploy($vid) {
// If the vocabulary isn't there then bail.
$vocabulary = taxonomy_vocabulary_load($vid);
if (!$vocabulary) {
return FALSE;
}
// Normally, like with users and nodes, the uuid is added to the object in the 'load'
// op of their hook. Taxonomy terms and vocabs have no load op, so we have to
// get it by hand.
$uuid = deploy_uuid_get_vocabulary_uuid($vid);
$remote_key = deploy_get_remote_key($uuid, 'vocabulary');
$vocabulary->vid = isset($remote_key['vid']) ? $remote_key['vid'] : NULL;
$vocabulary->uuid = $uuid;
return deploy_send(array(
'taxonomy.saveVocabulary',
), array(
$vocabulary,
));
}
/**
* Implementation of hook_deploy_check_cleanup().
*
* After dependencies are sorted out, but before items get pushed, we need to
* arrange the weights for our taxonomy terms such that parent terms are always
* pushed out before child terms. This is more difficult than one might think.
* I originally intended on having every term add itself as min(weight) - 1, but
* this doesn't always work out. For instance, a term will add its parent at a lower
* weight, but then a later term with the same parent might add itself at an even
* lower weight. What we need is to get all the terms and their dependent terms
* added, and then sort the weighting out. This is what we do here.
*/
function taxonomy_deploy_deploy_check_cleanup($pid) {
if (db_result(db_query("SELECT DISTINCT module FROM {deploy_plan_items} WHERE pid = %d AND module = 'taxonomy_term'", $pid))) {
// All that matters is that within a given vocabulary, all items are weighted
// such that the parents are of a lower weight than the children. The actual
// weights don't matter, and they don't need to be unique. This is the fastest
// thing I could figure out to meet that need.
// Get all the vids we are deploying terms for/
$vocabularies = db_query("SELECT DISTINCT vid FROM {term_data} td INNER JOIN {deploy_plan_items} dpi ON td.tid = dpi.data WHERE dpi.module = 'taxonomy_term'");
while ($vid = db_result($vocabularies)) {
// Get the tree for this vid, which is a sorted array of taxonomy term objects.
$tree = taxonomy_get_tree($vid);
// In order for this to be useful to us we strip it down to just an array
// of tids, still properly sorted. This involves re-iterating the tree but
// I don't see what to do about that.
foreach ($tree as &$value) {
$value = $value->tid;
}
// Now get all the tids we're deploying from this vocabulary, and get them in
// another array.
$items = array();
$tids = db_query("SELECT dpi.data FROM {deploy_plan_items} dpi INNER JOIN {term_data} td ON dpi.data = td.tid WHERE dpi.module = 'taxonomy_term' AND td.vid = %d", $vid);
while ($item = db_result($tids)) {
$items[] = $item;
}
// What we have now are two arrays - one sorted array of all tids in a vocabulary, and one
// unsorted array of all tids in our plan. what we want is one sorted array of all tids in
// the plan. Thank you array_intersect(). NOTE: the order of the parameters here matters
// immensely.
$items = array_intersect($tree, $items);
// Array_intersect() maintains the original array's keys, which we use as our
// weights. Again, I would love to know a better way to update these then running
// an update query on them all individually.
foreach ($items as $key => $item) {
db_query("UPDATE {deploy_plan_items} SET weight = %d WHERE data = %d and module = 'taxonomy_term'", $key, $item);
}
}
}
}
Functions
Name | Description |
---|---|
taxonomy_deploy_check_taxonomy | Manage the dependencies for an array of taxonomy terms. |
taxonomy_deploy_deploy_check_cleanup | Implementation of hook_deploy_check_cleanup(). |
taxonomy_deploy_menu | Implementation of hook_menu(). |
taxonomy_deploy_node_deploy_check | Implementation of hook_node_deploy_check(). |
taxonomy_term_deploy | Implementation of hook_deploy(). |
taxonomy_vocabulary_deploy | Implementation of hook_deploy(). |