Only in nat: .DS_Store
diff -rup nat-HEAD/nat.module nat/nat.module
--- nat-HEAD/nat.module 2007-12-17 00:03:49.000000000 -0800
+++ nat/nat.module 2008-02-05 02:11:53.000000000 -0800
@@ -15,9 +15,11 @@
* o Filter handling for body/description fields.
* o Duplicate handling?
*
- * Features to be added:
+ * Features recently added:
* o Node deletes: Optionally delete child nodes associated via NAT.
- * o Maintain hierarchy on unassociated vocabularies (on a best effort basis?)
+ * o Maintain hierarchy on unassociated vocabularies
+ * o Sync terms -> nodes, term depth can determine nodetype
+ * o i18n language for term: Optionally add i18n language data to term
*/
/**
@@ -96,24 +98,19 @@ function nat_nodeapi(&$node, $op, $tease
$node->nat = nat_get_terms($node->nid);
break;
case 'insert':
- $body = $node->body;
- // Copying over the node body is optional.
- $body = isset($nat_config['body'][$node->type]) ? $body : '';
+ // if terms already exist then this node was created from a sync
+ if(isset($node->nat)) {
+ break;
+ }
// Add node title as terms.
- $terms = _nat_add_terms($nat_config['types'][$node->type], $node->title, $body, $node->taxonomy, $node->nat['related'], $node->nat['synonyms']);
+ $terms = _nat_add_terms($nat_config['types'][$node->type], $node);
// Save node-term association in the NAT table.
_nat_save_association($node->nid, $terms);
break;
case 'update':
- $body = $node->body;
- // Copying over the node body is optional.
- $body = isset($nat_config['body'][$node->type]) ? $body : '';
-
- // Update node title in term(s).
- $terms = nat_get_terms($node->nid);
- _nat_update_terms($terms, $node->title, $body, $node->taxonomy, $node->nat['related'], $node->nat['synonyms']);
+ _nat_update_node_terms($node);
break;
case 'delete':
// Deleting the associated term when a node is deleted is optional.
@@ -127,6 +124,26 @@ function nat_nodeapi(&$node, $op, $tease
}
/**
+ * Implementation of hook_taxonomy().
+ */
+function nat_taxonomy($op, $type, $id) {
+
+ if($op == 'delete' && $type == 'term') {
+ $config = _nat_variable_get();
+
+ // term has already been deleted - so nat_get_nids() will not work
+ $result = db_query("SELECT nat.nid, node.type FROM {nat} nat INNER JOIN {node} node USING (nid) WHERE nat.tid = %d",$id['tid']);
+
+ // delete all nat associated nodetypes set for deletion
+ while ($node = db_fetch_object($result)) {
+ if($config['delete_node'][$node->type] == 1) {
+ node_delete($node->nid);
+ }
+ }
+ }
+}
+
+/**
* Implementation of hook_form_alter().
*/
function nat_form_alter($form_id, &$form) {
@@ -235,6 +252,18 @@ function nat_settings_form() {
'#default_value' => isset($nat_config['delete'][$type]) ? $nat_config['delete'][$type] : 0,
'#parents' => array('delete', $type)
);
+ $form['nat_'. $type]['delete_node'. $type] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Delete associated node if a term is deleted.'),
+ '#default_value' => isset($nat_config['delete_node'][$type]) ? $nat_config['delete_node'][$type] : 0,
+ '#parents' => array('delete_node', $type)
+ );
+ $form['nat_'. $type]['add_language'. $type] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Add i18n language information to term.'),
+ '#default_value' => isset($nat_config['add_language'][$type]) ? $nat_config['add_language'][$type] : 0,
+ '#parents' => array('add_language', $type)
+ );
$form['nat_'. $type]['related_'. $type] = array(
'#type' => 'checkbox',
'#title' => t('Allow users to define synonyms and related terms when they create and edit nodes.'),
@@ -261,6 +290,8 @@ function nat_settings_form_submit($form_
$form_values['body'] = array_filter($form_values['body']);
$form_values['delete'] = array_filter($form_values['delete']);
+ $form_values['delete_node'] = array_filter($form_values['delete_node']);
+ $form_values['add_language'] = array_filter($form_values['add_language']);
$form_values['node_links'] = array_filter($form_values['node_links']);
$form_values['related'] = array_filter($form_values['related']);
@@ -282,30 +313,63 @@ function nat_sync_form() {
$nat_config = _nat_variable_get();
$options = array();
+ $form['sync'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Sync associations'),
+ '#description' => t('The Sync operation will create NAT associations (and terms or nodes) for nodes or terms (marked for NAT association) but not present in the NAT table'),
+ '#collapsible' => TRUE
+ );
+ $form['sync']['terms_to_nodes'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Create nodes from existing terms'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
foreach ($nat_config['types'] as $type => $associations) {
if (!empty($associations)) {
foreach ($associations as $vid) {
- $options[$type .'|'. $vid] = t('@type ‹-› !vocabulary', array('@type' => $type, '!vocabulary' => $vocabularies[$vid]));
+ $vocab_options[$type .'|'. $vid] = t('Unassociated @type nodes will create --› !vocabulary terms', array('@type' => $type, '!vocabulary' => $vocabularies[$vid]));
+
+ $node_options = array('no'=>'','all' =>'from all vocabulary depths');
+ $tree = taxonomy_get_tree($vid);
+ $maxdepth = _array_depth($tree);
+
+ if($maxdepth) {
+ while($maxdepth >= 0) {
+ $node_options[$maxdepth] = t('only from terms at depth') . ' ' . $maxdepth;
+ --$maxdepth;
+ }
+ }
+
+ $form['sync']['terms_to_nodes']["$type"] = array(
+ '#type' => 'select',
+ '#title' => t('Unassociated !vocabulary terms will create --› @type nodes', array('@type' => $type, '!vocabulary' => $vocabularies[$vid])),
+ '#description' => t('Any terms not already NAT associated with the selected node types will be associated.'),
+ '#required' => FALSE,
+ '#options' => $node_options
+ );
+
+ // $node_options[$type .'|'. $vid] = t('Unassociated !vocabulary terms will create --› @type nodes', array('@type' => $type, '!vocabulary' => $vocabularies[$vid]));
}
}
}
- if (empty($options)) {
+ if (empty($vocab_options)) {
drupal_set_message(t('There are no vocabularies available to sync.'));
drupal_goto('admin/settings/nat');
}
- $form['sync'] = array(
+ $form['sync']['nodes_to_terms'] = array(
'#type' => 'fieldset',
- '#title' => t('Sync associations'),
- '#description' => t('The Sync operation will create NAT associations (and terms) for nodes (marked for NAT association) not present in the NAT table.'),
- '#collapsible' => TRUE
+ '#title' => t('Create terms from existing nodes'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
);
- $form['sync']['vocabularies'] = array(
+ $form['sync']['nodes_to_terms']['vocabularies'] = array(
'#type' => 'checkboxes',
- '#title' => t('Select the vocabularies to sync with associated node tables'),
+ '#title' => t('Select the node types to sync with associated vocabularies'),
'#description' => t('Any nodes not already NAT associated with the selected vocabularies will be associated.'),
- '#required' => TRUE,
- '#options' => $options
+ '#required' => FALSE,
+ '#options' => $vocab_options
);
$form['submit'] = array('#type' => 'submit', '#value' => t('Sync tables'));
@@ -316,7 +380,8 @@ function nat_sync_form() {
* Process NAT sync form submissions.
*/
function nat_sync_form_submit($form_id, $form_values) {
- _nat_sync_associations(array_filter($form_values['vocabularies']));
+ _nat_sync_associations_vocab(array_filter($form_values['vocabularies']));
+ _nat_sync_associations_nodes($form_values);
}
/**
@@ -550,33 +615,42 @@ function _nat_get_vocabularies() {
/**
* Add node titles as terms into the taxonomy system.
- * @todo Ideas are welcome to allow retaining the hierarchy for vocabularies not
- * present in the node form.
*
* @param $vids
* An array of vocabulary IDs denoting the vocabularies into which a NAT term
* is to be added.
- * @param $title
- * Node title.
- * @param $body
- * Node body.
- * @param $hierarchy
- * The taxonomy array for the node in question. This is used to, if set,
- * insert the new term as a child term of the selected parent.
+ * @param $node
+ * Complete node.
* @return $tids
* An array of term objects.
*/
-function _nat_add_terms($vids, $title, $body, $hierarchy = array(), $relations = array(), $synonyms = NULL) {
+function _nat_add_terms($vids, $node) {
+
+ $nat_config = _nat_variable_get();
+
+ $title = $node->title;
+
+ // Copying over the node body is optional.
+ $body = isset($nat_config['body'][$node->type]) ? $node->body : '';
+
+ $hierarchy = $node->taxonomy;
+ $relations = isset($node->nat['related']) ? $node->nat['related'] : array();
+ $synonyms = $node->nat['synonyms'];
+
$edit = array(
'name' => $title,
'description' => $body,
- 'weight' => 0
+ 'weight' => 0,
);
if (!empty($synonyms)) {
$edit['synonyms'] = $synonyms;
}
+ if (isset($node->language) && $nat_config['add_language'][$node->type] == 1) {
+ $edit['language'] = $node->language;
+ }
+
$tids = array();
foreach ($vids as $vid) {
@@ -607,31 +681,52 @@ function _nat_add_terms($vids, $title, $
/**
* Update saved node-terms.
*
- * @param $terms
- * An array of existing NAT-term objects.
- * @param $title
- * Title of the node.
- * @param $body
- * Body of the node.
- * @param $hierarchy
- * The taxonomy array for the node in question. This is used to, if set,
- * insert the new term as a child term of the selected parent.
+ * @param $node
+ * Node for which terms should be updated
*/
-function _nat_update_terms($terms, $title, $body, $hierarchy, $relations = array(), $synonyms = null) {
+function _nat_update_node_terms($node) {
+
+ $nat_config = _nat_variable_get();
+
+ $terms = nat_get_terms($node->nid);
+
+ // Update node title in term(s).
+ $title = $node->title;
+
+ // Copying over the node body is optional.
+ $body = isset($nat_config['body'][$node->type]) ? $node->body : '';
+
+ $hierarchy = $node->taxonomy;
+ $relations = isset($node->nat['related']) ? $node->nat['related'] : array();
+ $synonyms = $node->nat['synonyms'];
+
$edit = array(
'name' => $title,
'description' => $body,
- 'weight' => 0
);
if (!empty($synonyms)) {
$edit['synonyms'] = $synonyms;
}
+ if (isset($node->language) && $nat_config['add_language'][$node->type] == 1) {
+ $edit['language'] = $node->language;
+ }
+
foreach ($terms as $term) {
if (isset($hierarchy[$term->vid])) {
$edit['parent'] = $hierarchy[$term->vid];
}
+ elseif(count(taxonomy_get_parents($term->tid))) {
+ // preserves term's parent if it exists
+ $parents = taxonomy_get_parents($term->tid);
+
+ // $parents is an object but taxonomy_save_term expects an array
+ foreach($parents as $parent) {
+ $parent_array[] = array($parent->tid => $parent->tid);
+ }
+ $edit['parent'] = $parent_array;
+ }
else {
$edit['parent'] = array();
}
@@ -641,6 +736,7 @@ function _nat_update_terms($terms, $titl
}
$edit['tid'] = $term->tid;
+
taxonomy_save_term($edit);
}
}
@@ -690,8 +786,8 @@ function _nat_delete_association($nid) {
* @param $associations
* Associative array denoting the node-vocabulary pair that is to be synced.
*/
-function _nat_sync_associations($associations) {
- $nat_config = _nat_variable_get();
+function _nat_sync_associations_vocab($associations) {
+ $nat_config = variable_get('nat_config', array());
$counter = 0;
foreach ($associations as $association) {
@@ -703,7 +799,7 @@ function _nat_sync_associations($associa
$body = isset($nat_config['body'][$node['type']]) ? $node['body'] : '';
// Add node title as terms.
- $terms = _nat_add_terms(array($association[1]), $node['title'], $body);
+ $terms = _nat_add_terms(array($association[1]), $node);
// Save node-term association in the NAT table.
_nat_save_association($node['nid'], $terms);
@@ -711,7 +807,117 @@ function _nat_sync_associations($associa
$counter++;
}
}
- drupal_set_message(t('NAT sync complete: %count nodes synced.', array('%count' => $counter)));
+ if($counter > 0) {
+ drupal_set_message(t('NAT sync complete: %count nodes->terms synced.', array('%count' => $counter)));
+ }
+}
+
+/**
+ * Synchronize NAT node-term relationships. Create associated nodes for terms
+ * where missing.
+ *
+ * @param $associations
+ * Associative array denoting the node-vocabulary pair that is to be synced.
+ */
+function _nat_sync_associations_nodes($form_values) {
+
+ global $user;
+
+ $vocabularies = _nat_get_vocabularies();
+ $nat_config = variable_get('nat_config', array());
+
+ $counter = array();
+ foreach ($nat_config['types'] as $type => $associations) {
+ if (!empty($associations) && $form_values[$type] != 'no') {
+ foreach ($associations as $vid) {
+
+ // get terms for vocabulary
+ $terms = taxonomy_get_tree($vid);
+
+ foreach($terms as $key => $term) {
+
+ if($term->depth == $form_values[$type] || $form_values[$type] == 'all') {
+
+ // find node nid associated with term
+ $natnid = db_fetch_object(db_query('SELECT n.nid FROM {nat} n WHERE n.tid = %d', $term->tid));
+
+ // if no associated node - then create and save node
+ if(!is_numeric($natnid->nid)) {
+
+ // build node
+ $new_node = (object)$node;
+ $new_node->type = $type;
+ node_object_prepare($new_node);
+ $new_node->title = $term->name;
+ $new_node->status = 1;
+
+ $parent = taxonomy_get_parents($term->tid);
+ if($parent) {
+ $new_node->taxonomy = array('$association[1]' => current($parent)->tid);
+ }
+
+ $new_node->body = isset($nat_config['body'][$association[0]]) ? $term->description : '';
+ $new_node->uid = $user->uid;
+ $new_node->nat = 1; // set so that new term is not created when node_api hook is called
+
+ // save node
+ node_save($new_node);
+
+ // save association now that we have a nid
+ _nat_save_association($new_node->nid, array(array('tid'=>$term->tid,'vid'=>$association[1])));
+
+ ++$counter[$type];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(count($counter)) {
+ foreach($counter as $key => $value) {
+ drupal_set_message(t('NAT sync complete: %value terms --> %key nodes synced.', array('%value' => $value, '%key' => $key)));
+ }
+ }
+}
+
+/**
+ * Find maximum depth of a vocabulary
+ *
+ * @param $vid
+ * vid of the vocabulary
+ * @return $depth
+ * An integer with max depth
+ */
+
+function _vocabulary_depth($vid) {
+
+ $tree = taxonomy_get_tree($vid);
+ $depth = _array_depth($tree);
+
+ return $depth;
+}
+
+/**
+ * Find maximum depth of an array
+ *
+ * @param $array
+ * Associative array denoting the node-vocabulary pair that is to be synced.
+ * @param $depthcount
+ * For internal use
+ * @return $depthcount
+ * An integer with max depth
+ */
+
+function _array_depth($array) {
+
+ $depth = 0;
+ foreach ($array as $value) {
+ if($value->depth > $depth) {
+ $depth = $value->depth;
+ }
+ }
+ return $depth;
}
/**
@@ -730,7 +936,9 @@ function _nat_variable_get($name = NULL)
'types' => array(),
'body' => array(),
'delete' => array(),
- 'node_links' => array()
+ 'node_links' => array(),
+ 'add_language' => array(),
+ 'delete_node' => array(),
);
$variables = variable_get('nat_config', array());
$variables = array_merge($defaults, $variables);