View source
<?php
namespace HookUpdateDeployTools;
class Nodes implements ImportInterface, ExportInterface {
public static function import($node_paths) {
$t = get_t();
$completed = array();
$node_paths = (array) $node_paths;
$total_requested = count($node_paths);
try {
self::canImport();
foreach ($node_paths as $key => $node_path) {
$filename = self::normalizeFileName($node_path);
$path = self::normalizePathName($node_path);
if (HudtInternal::canReadFile($filename, 'node')) {
$file_contents = HudtInternal::readFileToString($filename, 'node');
eval('$node_import = ' . $file_contents . ';');
if (!is_object($node_import)) {
if (empty($errors)) {
$errors = 'Node build error on eval().';
}
$message = 'Unable to get a node from the import. Errors: @errors';
throw new HudtException($message, array(
'@errors' => $errors,
), WATCHDOG_ERROR);
}
$error_msg = '';
$result = self::processOne($node_import, $path);
$message = '@operation: @path - successful.';
global $base_url;
$link = "{$base_url}/{$result['edit_link']}";
$vars = array(
'@operation' => $result['operation'],
'@path' => $path,
);
Message::make($message, $vars, WATCHDOG_INFO, 1, $link);
$completed[$path] = $result['operation'];
}
}
} catch (\Exception $e) {
$vars = array(
'!error' => method_exists($e, 'logMessage') ? $e
->logMessage() : $e
->getMessage(),
);
if (!method_exists($e, 'logMessage')) {
$message = 'Node import denied because: !error';
Message::make($message, $vars, WATCHDOG_ERROR);
}
$done = HudtInternal::getSummary($completed, $total_requested, 'Imported');
Message::make($done, array(), FALSE, 1);
throw new HudtException('Caught Exception: Update aborted! !error', $vars, WATCHDOG_ERROR, FALSE);
}
$done = HudtInternal::getSummary($completed, $total_requested, 'Imported Nodes');
return $done;
}
public static function canImport() {
$clean_urls = variable_get('clean_url', FALSE);
if ($clean_urls) {
return TRUE;
}
else {
$message = "Node import from file, requires clean URLs, which are not enabled. Please enable Clean URLs.";
throw new HudtException($message, array(), WATCHDOG_ERROR, TRUE);
}
}
public static function canExport() {
$file = DRUPAL_ROOT . '/includes/utility.inc';
require_once $file;
$clean_urls = variable_get('clean_url', FALSE);
if ($clean_urls) {
return TRUE;
}
else {
$message = "Node export to a file, requires clean URLs, which are not enabled. Please enable Clean URLs.";
throw new HudtException($message, array(), WATCHDOG_ERROR, TRUE);
}
}
public static function normalizeFileName($quasi_name) {
$quasi_name = trim($quasi_name, '/');
$items = array(
'.txt' => '',
'/' => 'zZz',
);
$file_name = str_replace(array_keys($items), array_values($items), $quasi_name);
$file_name = "{$file_name}.txt";
return $file_name;
}
public static function normalizePathName($quasi_path) {
$items = array(
'.txt' => '',
'zZz' => '/',
);
$path = str_replace(array_keys($items), array_values($items), $quasi_path);
return $path;
}
private static function processOne($node_import, $path) {
$language = !empty($node_import->language) ? $node_import->language : LANGUAGE_NONE;
$node_existing = self::getNodeFromPath($path, $language);
$initial_vid = FALSE;
$msg_vars = array(
'@path' => $path,
'@language' => $language,
);
if (!empty($node_existing)) {
$operation = t('Updated');
$op = 'update';
$initial_vid = $node_existing->vid;
$saved_node = self::updateExistingNode($node_import, $node_existing);
}
else {
$exists = self::pathExists($path, $language);
if ($exists) {
$message = "The path belongs to something that is not a node. Import of @language: @path failed.";
throw new HudtException($message, $msg_vars, WATCHDOG_ERROR, TRUE);
}
$operation = t('Created');
$op = 'create';
$saved_node = self::createNewNode($node_import);
}
$msg_vars['@operation'] = $operation;
$saved_path = !empty($saved_node->nid) ? drupal_lookup_path('alias', "node/{$saved_node->nid}", $saved_node->language) : FALSE;
switch (TRUE) {
case empty($saved_node->nid):
$message = '@operation of @language: @path failed: The saved node ended up with no nid.';
$valid = FALSE;
break;
case $saved_path !== $path:
$msg_vars['@savedpath'] = $saved_path;
$message = '@operation failure: The paths do not match. Intended Path: @path Saved Path: @savedpath';
$valid = FALSE;
break;
case $saved_node->title !== $node_import->title:
$msg_vars['@intended_title'] = $node_import->title;
$msg_vars['@saved_title'] = $saved_node->title;
$message = '@operation failure: The titles do not match. Intended title: @intended_title Saved Title: @saved_title';
$valid = FALSE;
break;
default:
$valid = TRUE;
}
if (!$valid) {
self::rollbackImport($op, $saved_node, $initial_vid);
throw new HudtException($message, $msg_vars, WATCHDOG_ERROR, TRUE);
}
$return = array(
'node' => $saved_node,
'operation' => "{$operation}: node/{$saved_node->nid}",
'edit_link' => "node/{$saved_node->nid}/edit",
);
return $return;
}
public static function rollbackImport($op, $node, $rollback_to_vid) {
if ($op === 'create') {
if (!empty($node->nid)) {
node_delete($node->nid);
$msg = "Node @nid created but failed validation and was deleted.";
$variables = array(
'@nid' => $node->nid,
);
Message::make($msg, $variables, WATCHDOG_INFO, 1);
}
}
else {
$revision_list = node_revision_list($node);
$revision_id_to_rollback = $node->vid;
unset($revision_list[$revision_id_to_rollback]);
if (count($revision_list) > 0) {
$last_revision = max(array_keys($revision_list));
$node_last_revision = node_load($node->nid, $rollback_to_vid);
node_save($node_last_revision);
node_revision_delete($revision_id_to_rollback);
$msg = "Node @nid updated but failed validation, Revision @deleted deleted and rolled back to revision @rolled_to.";
$variables = array(
'@nid' => $node->nid,
'@deleted' => $revision_id_to_rollback,
'@rolled_to' => $rollback_to_vid,
);
Message::make($msg, $variables, WATCHDOG_INFO, 1);
}
}
}
public static function createNewNode($node) {
$saved_node = clone $node;
unset($saved_node->nid);
unset($saved_node->workbench_moderation);
if (!empty($node->workbench_moderation)) {
$saved_node->workbench_moderation_state_current = $node->workbench_moderation['current']->state;
$saved_node->workbench_moderation_state_new = $node->workbench_moderation['current']->state;
}
$saved_node->revision = 1;
$saved_node->is_new = TRUE;
unset($saved_node->vid);
$log = !empty($saved_node->log) ? $saved_node->log : '';
$message = t("Created from import file by hook_update_deploy_tools Node import.");
$saved_node->log = "{$message}\n {$log}";
node_save($saved_node);
return $saved_node;
}
public static function updateExistingNode($node, $node_existing) {
$saved_node = clone $node;
$saved_node->nid = $node_existing->nid;
$saved_node->revision = 1;
$saved_node->is_new = FALSE;
$log = !empty($saved_node->log) ? $saved_node->log : '';
$message = t("Updated from import file by hook_update_deploy_tools Node import.");
$saved_node->log = "{$message}\n {$log}";
unset($saved_node->workbench_moderation);
if (!empty($node->workbench_moderation) && !empty($node_existing->workbench_moderation)) {
$saved_node->workbench_moderation_state_current = $node->workbench_moderation['current']->state;
$saved_node->workbench_moderation_state_new = $node->workbench_moderation['current']->state;
}
node_save($saved_node);
return $saved_node;
}
public static function getNodeFromPath($path, $language) {
$node = FALSE;
$source_path = drupal_lookup_path('source', $path, $language);
$source_path_parts = explode('/', $source_path);
if (!empty($source_path_parts[0]) && $source_path_parts[0] === 'node' && !empty($source_path_parts[1])) {
$nid = $source_path_parts[1];
$nodes = entity_load('node', array(
$nid,
));
$node = $nodes[$nid];
}
return $node;
}
public static function pathExists($path, $language) {
$exists = FALSE;
$source_path = drupal_lookup_path('source', $path, $language);
if (!empty($source_path)) {
$exists = TRUE;
}
else {
$useable_path = !empty($source_path) ? $source_path : $path;
$valid = drupal_valid_path($useable_path);
if ($valid) {
$exists = TRUE;
}
}
return $exists;
}
public static function export($nid) {
$t = get_t();
try {
Check::notEmpty('nid', $nid);
Check::isNumeric('nid', $nid);
self::canExport();
$msg_return = '';
$node = node_load($nid);
Check::notEmpty('node', $node);
$storage_path = HudtInternal::getStoragePath('node');
$node_path = drupal_lookup_path('alias', "node/{$nid}");
Check::notEmpty('node alias', $node_path);
$node_path = self::normalizePathName($node_path);
$file_name = self::normalizeFileName($node_path);
$file_uri = DRUPAL_ROOT . '/' . $storage_path . $file_name;
$export_contents = drupal_var_export($node);
$msg_return = HudtInternal::writeFile($file_uri, $export_contents);
} catch (\Exception $e) {
$e->logIt = FALSE;
$vars = array(
'!error' => method_exists($e, 'logMessage') ? $e
->logMessage() : $e
->getMessage(),
);
$msg_error = $t("Caught exception: !error", $vars);
}
if (!empty($msg_error)) {
drush_log($msg_error, 'error');
}
return !empty($msg_return) ? $msg_return : $msg_error;
}
public static function modifySimpleFieldValue($nid, $field, $value) {
$t = get_t();
$simple_fields = array(
'title',
'status',
'language',
'tnid',
'sticky',
'promote',
'comment',
'uid',
'translate',
);
$variables = array(
'!nid' => $nid,
'!fieldname' => $field,
'!value' => $value,
);
if (in_array($field, $simple_fields)) {
$node = node_load($nid);
if (!empty($node)) {
if (isset($node->{$field})) {
$node->{$field} = $value;
$node = node_save($node);
$message = "On Node !nid, the field value of '!fieldname' was changed to '!value'.";
return Message::make($message, $variables, WATCHDOG_INFO);
}
else {
$message = "The field '!fieldname' does not exist on the node !nid so it could not be altered.";
Message::make($message, $variables, WATCHDOG_ERROR);
throw new HudtException($message, $variables, WATCHDOG_ERROR, FALSE);
}
}
else {
$message = "The node '!nid' does not exist, so can not be updated.";
Message::make($message, $variables, WATCHDOG_ERROR);
throw new HudtException($message, $variables, WATCHDOG_ERROR, FALSE);
}
}
else {
$message = "The field '!fieldname' is not a simple field and can not be changed by the method ::modifySimpleFieldValue.";
Message::make($message, $variables, WATCHDOG_ERROR);
throw new HudtException($message, $variables, WATCHDOG_ERROR, FALSE);
}
}
public static function rebuildNodeAccess(&$sandbox) {
if (empty($sandbox['sandbox']['progress'])) {
db_delete('node_access')
->execute();
$sandbox['messages'] = array();
$sandbox['messages'][] = Message::make('Deleted table node_access. Rebuilding the node access table.', array(), WATCHDOG_INFO);
$sandbox['iteration'] = 0;
$sandbox['progress'] = 1;
}
_node_access_rebuild_batch_operation($sandbox);
$sandbox['iteration']++;
$sandbox['#finished'] = $sandbox['sandbox']['progress'] >= $sandbox['sandbox']['max'];
if ($sandbox['#finished']) {
node_access_needs_rebuild(FALSE);
$num_rows = db_select('node_access')
->countQuery()
->execute()
->fetchField();
$variables = array(
'!rows' => $num_rows,
'!iterations' => $sandbox['iteration'],
);
$messages = implode(' ', $sandbox['messages']);
$messages .= Message::make('node_access table rebuilt !rows rows in !iterations batches.', $variables, WATCHDOG_INFO);
return $messages;
}
else {
$variables = array(
'!percent' => round($sandbox['sandbox']['progress'] / $sandbox['sandbox']['max'] * 100, 1),
'!iteration' => $sandbox['iteration'],
'!progress' => $sandbox['sandbox']['progress'],
'!max' => $sandbox['sandbox']['max'],
);
return t("#!iteration Rebuilding node_access_table (!progress/!max) -> !percent%", $variables);
}
}
}