| 1 |
<?php
|
| 2 |
|
| 3 |
// $Id$
|
| 4 |
|
| 5 |
/**
|
| 6 |
* Syncronize form. Contains lists of updated, added, and deleted templates.
|
| 7 |
*
|
| 8 |
* @return
|
| 9 |
* The rendered HTML of the page.
|
| 10 |
*/
|
| 11 |
function skeleton_sync_page() {
|
| 12 |
drupal_add_js(drupal_get_path('module', 'skeleton') . '/skeleton-admin.js');
|
| 13 |
$output .= drupal_get_form('skeleton_sync_content_form');
|
| 14 |
$output .= drupal_get_form('skeleton_sync_add_template_form');
|
| 15 |
$output .= drupal_get_form('skeleton_sync_delete_template_form');
|
| 16 |
return $output;
|
| 17 |
}
|
| 18 |
|
| 19 |
/**
|
| 20 |
* Syncronize content form.
|
| 21 |
*
|
| 22 |
* @param $form_state
|
| 23 |
* The state of the form.
|
| 24 |
* @return
|
| 25 |
* The form array.
|
| 26 |
*/
|
| 27 |
function skeleton_sync_content_form($form_state) {
|
| 28 |
$form = array();
|
| 29 |
$form['content'] = array(
|
| 30 |
'#type' => 'fieldset',
|
| 31 |
'#title' => t('Syncronize template content'),
|
| 32 |
'#collapsible' => TRUE,
|
| 33 |
);
|
| 34 |
$form['content']['help'] = array(
|
| 35 |
'#prefix' => '<p>',
|
| 36 |
'#suffix' => '</p>',
|
| 37 |
'#value' => t('Use this form to syncronize changed templates with pages which have all ready been created.'),
|
| 38 |
);
|
| 39 |
|
| 40 |
// Build the list of pages which have had content changes.
|
| 41 |
$updated = array();
|
| 42 |
$result = db_query("SELECT stn.nid, stn.template_id, st.template FROM {skeleton_template_node} stn INNER JOIN {skeleton_template} st ON stn.template_id = st.template_id WHERE template_status = '%s'", 'updated');
|
| 43 |
while ($eligble_node = db_fetch_object($result)) {
|
| 44 |
$node = node_load($eligble_node->nid);
|
| 45 |
$book = node_load($node->book['bid']);
|
| 46 |
$updated[$node->nid] = t('<a href="@node-url">%title</a>, in the <a href="@book-url">%book-title</a> book, created from the <a href="@template-url">%template</a> template.', array('@node-url' => url('node/' . $node->nid), '%title' => $node->title, '@book-url' => url('node/' . $book->nid), '%book-title' => $book->title, '%template' => $eligble_node->template, '@template-url' => url('admin/content/skeleton/template/' . $eligble_node->template_id . '/view')));
|
| 47 |
}
|
| 48 |
if (!empty($updated)) {
|
| 49 |
$form['content']['#collapsed'] = FALSE;
|
| 50 |
$form['content']['nodes'] = array(
|
| 51 |
'#type' => 'checkboxes',
|
| 52 |
'#title' => t('Select the nodes you wish to update'),
|
| 53 |
'#options' => $updated,
|
| 54 |
);
|
| 55 |
$form['content']['submit'] = array(
|
| 56 |
'#type' => 'submit',
|
| 57 |
'#value' => t('Synchronize'),
|
| 58 |
);
|
| 59 |
}
|
| 60 |
else {
|
| 61 |
$form['content']['#collapsed'] = TRUE;
|
| 62 |
$form['content']['no_nodes'] = array(
|
| 63 |
'#prefix' => '<p>',
|
| 64 |
'#suffix' => '</p>',
|
| 65 |
'#value' => t('There are no nodes eligible for content synchronizing.')
|
| 66 |
);
|
| 67 |
}
|
| 68 |
return $form;
|
| 69 |
}
|
| 70 |
|
| 71 |
/**
|
| 72 |
* Submit handler for the syncronize content form.
|
| 73 |
*
|
| 74 |
* @param $form
|
| 75 |
* The form being submitted.
|
| 76 |
*
|
| 77 |
* @param $form_state
|
| 78 |
* The state of the form.
|
| 79 |
*/
|
| 80 |
function skeleton_sync_content_form_submit($form, $form_state) {
|
| 81 |
$batch = array(
|
| 82 |
'title' => t('Updating content'),
|
| 83 |
'init_message' => t('Content updating is starting.'),
|
| 84 |
'progress_message' => t('Processed @current out of @total.'),
|
| 85 |
'error_message' => t('There was an error while updating content.'),
|
| 86 |
'file' => drupal_get_path('module', 'skeleton'). '/skeleton_sync.inc',
|
| 87 |
);
|
| 88 |
foreach($form_state['values']['nodes'] as $nid) {
|
| 89 |
$batch['operations'][] = array('skeleton_sync_update_node', array($nid));
|
| 90 |
}
|
| 91 |
batch_set($batch);
|
| 92 |
}
|
| 93 |
|
| 94 |
/**
|
| 95 |
* Form for pushing out new templates to existing skeletons.
|
| 96 |
*/
|
| 97 |
function skeleton_sync_add_template_form($form_state) {
|
| 98 |
$form = array();
|
| 99 |
$form['templates'] = array(
|
| 100 |
'#type' => 'fieldset',
|
| 101 |
'#title' => t('Syncronize templates'),
|
| 102 |
'#collapsible' => TRUE,
|
| 103 |
);
|
| 104 |
// Find all copies of instantiated skeletons which do not contain a template
|
| 105 |
// now associated with the same skeleton.
|
| 106 |
$skeleton_result = db_query("SELECT DISTINCT skeleton_id FROM {skeleton_template_node}");
|
| 107 |
while ($skeleton_id = db_result($skeleton_result)) {
|
| 108 |
$templates = array();
|
| 109 |
$updated = array();
|
| 110 |
$skeleton = skeleton_load($skeleton_id);
|
| 111 |
$form['templates']['skeletons'] = array(
|
| 112 |
'#tree' => TRUE,
|
| 113 |
);
|
| 114 |
$form['templates']['skeletons'][$skeleton_id] = array();
|
| 115 |
$template_result = db_query("SELECT DISTINCT template_id FROM {skeleton_template_node} WHERE skeleton_id = %d", $skeleton_id);
|
| 116 |
while ($template_id = db_result($template_result)) {
|
| 117 |
$templates[] = $template_id;
|
| 118 |
}
|
| 119 |
$updated_result = db_query("SELECT template_id FROM {skeleton_data} WHERE skeleton_id = %d AND template_id NOT IN (" . implode(',', $templates) . ")", $skeleton_id);
|
| 120 |
while ($updated_id = db_result($updated_result)) {
|
| 121 |
$template = skeleton_template_load($updated_id);
|
| 122 |
$updated[$updated_id] = l($template->template, 'admin/content/skeleton/template/' . $template->template_id . '/view');
|
| 123 |
}
|
| 124 |
if (!empty($updated)) {
|
| 125 |
$form['templates']['skeletons'][$skeleton_id] = array(
|
| 126 |
'#type' => 'checkboxes',
|
| 127 |
'#title' => t('Create new pages from new templates assigned to <a href="@skeleton-url">%skeleton</a>', array('@skeleton-url' => url('admin/content/skeleton/skeleton/' . $skeleton->skeleton_id . '/edit'), '%skeleton' => $skeleton->skeleton)),
|
| 128 |
'#options' => $updated,
|
| 129 |
);
|
| 130 |
$form['templates']['submit'] = array(
|
| 131 |
'#type' => 'submit',
|
| 132 |
'#value' => t('Syncronize'),
|
| 133 |
);
|
| 134 |
}
|
| 135 |
else {
|
| 136 |
$form['templates']['#collapsed'] = TRUE;
|
| 137 |
$form['templates']['no_templates'] = array(
|
| 138 |
'#prefix' => '<p>',
|
| 139 |
'#suffix' => '</p>',
|
| 140 |
'#value' => t('There are no templates eligible for content synchronizing.')
|
| 141 |
);
|
| 142 |
}
|
| 143 |
}
|
| 144 |
return $form;
|
| 145 |
}
|
| 146 |
|
| 147 |
/**
|
| 148 |
* Submit handler for pushing out new templates to existing books.
|
| 149 |
*/
|
| 150 |
function skeleton_sync_add_template_form_submit($form, &$form_state) {
|
| 151 |
module_load_include('inc', 'node', 'node.pages');
|
| 152 |
module_load_include('inc', 'skeleton', 'skeleton_token');
|
| 153 |
foreach($form_state['values']['skeletons'] as $skeleton_id => $templates) {
|
| 154 |
$templates = array_filter($templates);
|
| 155 |
foreach($templates as $template_id) {
|
| 156 |
// Find the template parent of this template
|
| 157 |
// $template = skeleton_template_load($template_id);
|
| 158 |
// If the parent is 0, we place it under the top-most book node.
|
| 159 |
// Otherwise, place it under the parent template in the book.
|
| 160 |
$parent = db_result(db_query("SELECT parent FROM {skeleton_data} WHERE skeleton_id = %d AND template_id = %d", $skeleton_id, $template_id));
|
| 161 |
if ($parent == 0) {
|
| 162 |
// TODO!
|
| 163 |
}
|
| 164 |
else {
|
| 165 |
$parent_nids_result = db_query("SELECT nid, tokens FROM {skeleton_template_node} WHERE skeleton_id = %d AND template_id = %d", $skeleton_id, $parent);
|
| 166 |
while($parent_info = db_fetch_object($parent_nids_result)) {
|
| 167 |
$parent_info->tokens = unserialize($parent_info->tokens);
|
| 168 |
$data = db_result(db_query("SELECT node_data FROM {skeleton_template} WHERE template_id = %d", $template_id));
|
| 169 |
$node = array();
|
| 170 |
$node['values'] = unserialize($data);
|
| 171 |
$parent_node = node_load($parent_info->nid, NULL, TRUE);
|
| 172 |
$node['values']['book'] = array();
|
| 173 |
$node['values']['book']['bid'] = $parent_node->book['bid'];
|
| 174 |
$node['values']['book']['plid'] = $parent_node->book['mlid'];
|
| 175 |
$node['values']['book']['options'] = array();
|
| 176 |
|
| 177 |
// Allow use of the [bookpathalias] token from pathauto.
|
| 178 |
if (module_exists('pathauto')) {
|
| 179 |
$node['values']['title'] = str_replace('[bookpathalias]', drupal_get_path_alias($parent_node->path), $node['values']['title']);
|
| 180 |
$node['values']['body'] = str_replace('[bookpathalias]', drupal_get_path_alias($parent_node->path), $node['values']['body']);
|
| 181 |
}
|
| 182 |
|
| 183 |
// Replace custom tokens in the title and body fields. Replace skeleton
|
| 184 |
// tokens first so they may be used as node tokens such as [title].
|
| 185 |
if (!empty($parent_info->tokens)) {
|
| 186 |
$node = _skeleton_token_replace_values($node, 'skeleton', $parent_info->tokens);
|
| 187 |
}
|
| 188 |
|
| 189 |
$node = _skeleton_token_replace_values($node, 'node', $node);
|
| 190 |
|
| 191 |
$node['values']['uid'] = $parent_node->uid;
|
| 192 |
$node['values']['name'] = $parent_node->name;
|
| 193 |
|
| 194 |
$node['values']['tokens'] = $parent_info->tokens;
|
| 195 |
|
| 196 |
// We have to add the skeleton ID here as we can't save it with the
|
| 197 |
// template as a template may have multiple skeletons.
|
| 198 |
$node['values']['skeleton_id'] = $skeleton_id;
|
| 199 |
|
| 200 |
$node['values']['op'] = t('Save');
|
| 201 |
drupal_execute($node['values']['type'] .'_node_form', $node, (object)$node['values']);
|
| 202 |
// TODO: This will probably need to be removed if this call is integrated
|
| 203 |
// into the book module. See http://drupal.org/node/364529 for details.
|
| 204 |
menu_rebuild();
|
| 205 |
$form_state['nids'][] = $node['nid'];
|
| 206 |
}
|
| 207 |
}
|
| 208 |
}
|
| 209 |
}
|
| 210 |
}
|
| 211 |
|
| 212 |
/**
|
| 213 |
* Form for deleting instantiated templates where the source template has been
|
| 214 |
* deleted.
|
| 215 |
*/
|
| 216 |
function skeleton_sync_delete_template_form($form_state) {
|
| 217 |
$form = array();
|
| 218 |
$form['delete'] = array(
|
| 219 |
'#type' => 'fieldset',
|
| 220 |
'#title' => t('Delete instantiated template nodes'),
|
| 221 |
'#collapsible' => TRUE,
|
| 222 |
);
|
| 223 |
$form['delete']['help'] = array(
|
| 224 |
'#prefix' => '<p>',
|
| 225 |
'#suffix' => '</p>',
|
| 226 |
'#value' => t("Use this form to delete nodes where the associated template has also been deleted."),
|
| 227 |
);
|
| 228 |
$form['delete']['nodes'] = array(
|
| 229 |
'#tree' => TRUE,
|
| 230 |
);
|
| 231 |
|
| 232 |
// Find all nodes where the template it was created from has been deleted.
|
| 233 |
$result = db_query("SELECT nid from {skeleton_template_node} stn LEFT JOIN {skeleton_template} st ON stn.template_id = st.template_id WHERE st.template_id IS NULL");
|
| 234 |
$options = array();
|
| 235 |
while ($node = node_load(db_result($result))) {
|
| 236 |
$book = node_load($node->book['bid']);
|
| 237 |
$options[$node->nid] = t('<a href="@node-url">%title</a>, in the <a href="@book-url">%book-title</a> book.', array('@node-url' => url('node/' . $node->nid), '%title' => $node->title, '@book-url' => url('node/' . $book->nid), '%book-title' => $book->title));
|
| 238 |
}
|
| 239 |
if (!empty($options)) {
|
| 240 |
$form['delete']['nodes'] = array(
|
| 241 |
'#type' => 'checkboxes',
|
| 242 |
'#title' => t('Select the nodes you wish to delete'),
|
| 243 |
'#options' => $options,
|
| 244 |
);
|
| 245 |
$form['delete']['submit'] = array(
|
| 246 |
'#type' => 'submit',
|
| 247 |
'#value' => t('Delete selected nodes'),
|
| 248 |
);
|
| 249 |
}
|
| 250 |
else {
|
| 251 |
$form['delete']['#collapsed'] = TRUE;
|
| 252 |
$form['delete']['no_nodes'] = array(
|
| 253 |
'#prefix' => '<p>',
|
| 254 |
'#suffix' => '</p>',
|
| 255 |
'#value' => t('There are no nodes with deleted templates.')
|
| 256 |
);
|
| 257 |
}
|
| 258 |
return $form;
|
| 259 |
}
|
| 260 |
|
| 261 |
/**
|
| 262 |
* Submit handler for deleting nodes where the associated template has also
|
| 263 |
* been deleted.
|
| 264 |
*/
|
| 265 |
function skeleton_sync_delete_template_form_submit($form, &$form_state) {
|
| 266 |
$batch = array(
|
| 267 |
'title' => t('Deleting content'),
|
| 268 |
'init_message' => t('Content deletion is starting.'),
|
| 269 |
'progress_message' => t('Processed @current out of @total.'),
|
| 270 |
'error_message' => t('There was an error while updating content.'),
|
| 271 |
'file' => drupal_get_path('module', 'skeleton'). '/skeleton_sync.inc',
|
| 272 |
);
|
| 273 |
foreach (array_filter($form_state['values']['nodes']) as $nid) {
|
| 274 |
$batch['operations'][] = array('skeleton_sync_delete_node', array($nid));
|
| 275 |
}
|
| 276 |
if (!empty($batch['operations'])) {
|
| 277 |
batch_set($batch);
|
| 278 |
}
|
| 279 |
}
|
| 280 |
|
| 281 |
/**
|
| 282 |
* Update an instantiated node based on an updated template.
|
| 283 |
*
|
| 284 |
* @param $nid
|
| 285 |
* The node ID to be updated.
|
| 286 |
*
|
| 287 |
* @param &$context
|
| 288 |
* The current context of the batch operation.
|
| 289 |
*/
|
| 290 |
function skeleton_sync_update_node($nid, &$context) {
|
| 291 |
module_load_include('inc', 'skeleton', 'skeleton_token');
|
| 292 |
$node = node_load($nid);
|
| 293 |
$context['message'] = t('Updating %title', array('%title' => $node->title));
|
| 294 |
if (empty($node->skeleton_template->template_id)) {
|
| 295 |
$context['results'][] = t('Failed updating <a href="@node-url">%title</a> as it does not have an associated template.', array('@node-url' => url('node/' . $node->nid), '%title' => $node->title));
|
| 296 |
return;
|
| 297 |
}
|
| 298 |
$template = skeleton_template_load($node->skeleton_template->template_id);
|
| 299 |
// Unset the node teaser. If a module has added it, it will be applied in
|
| 300 |
// the foreach loop.
|
| 301 |
unset($node->teaser);
|
| 302 |
$template_node = (object)$template->node_data;
|
| 303 |
// Don't change the author of nodes.
|
| 304 |
unset($template_node->uid);
|
| 305 |
unset($template_node->name);
|
| 306 |
foreach ($template_node as $key => $value) {
|
| 307 |
$node->$key = $value;
|
| 308 |
}
|
| 309 |
// Replace body and title tokens.
|
| 310 |
$node = _skeleton_token_replace_values($node, 'skeleton', $node->skeleton_template->tokens);
|
| 311 |
$node = _skeleton_token_replace_values($node, 'node', $node);
|
| 312 |
|
| 313 |
// Add a flag so that we keep this node as "unmodified".
|
| 314 |
$node->skeleton_template->keep_connected = TRUE;
|
| 315 |
|
| 316 |
$node = node_submit($node);
|
| 317 |
node_save($node);
|
| 318 |
db_query("UPDATE {skeleton_template_node} SET template_status = 'synced' WHERE nid = %d", $node->nid);
|
| 319 |
$context['results'][] = t('Updated %title', array('%title' => $node->title));
|
| 320 |
}
|
| 321 |
|
| 322 |
/**
|
| 323 |
* Delete an instantiated node. This is used to delete nodes where it's
|
| 324 |
* template has also been deleted, but could also be used to delete any node.
|
| 325 |
*
|
| 326 |
* @param $nid
|
| 327 |
* The node ID to delete.
|
| 328 |
*
|
| 329 |
* @param &$context
|
| 330 |
* The current context of the batch operation.
|
| 331 |
*/
|
| 332 |
function skeleton_sync_delete_node($nid, &$context) {
|
| 333 |
$node = node_load($nid);
|
| 334 |
node_delete($nid);
|
| 335 |
$context['results'][] = t('Deleted %title', array('%title' => $node->title));
|
| 336 |
}
|