uuid_link.module in UUID Link 7
Same filename and directory in other branches
Provides a filter and UI for adding links to entities that are not affected by changes in URL alias.
File
uuid_link.moduleView source
<?php
/**
* @file
* Provides a filter and UI for adding links to entities that are not affected
* by changes in URL alias.
*/
/**
* Implements hook_permission().
*/
function uuid_link_permission() {
return array(
'access uuid link' => array(
'title' => t('Access UUID Link'),
'description' => t('Access UUID Link user interface.'),
),
);
}
/**
* Implements hook_menu().
*/
function uuid_link_menu() {
$items = array();
$items['uuid-link/autocomplete'] = array(
'page callback' => 'uuid_link_autocomplete',
'access arguments' => array(
'access uuid link',
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_wysiwyg_plugin().
*/
function uuid_link_wysiwyg_plugin($editor, $version) {
if ($editor == 'ckeditor') {
return array(
'uuid_link' => array(
'path' => drupal_get_path('module', 'uuid_link') . '/plugins/link/',
'load' => TRUE,
'extensions' => array(
'uuid_link' => t('Link to site content'),
),
),
);
}
}
/**
* Implements hook_element_info_alter().
*/
function uuid_link_element_info_alter(&$type) {
if (!empty($type['text_format'])) {
$type['form']['#post_render'][] = 'uuid_link_form_post_render';
}
}
/**
* Implements hook_entity_info_alter().
*/
function uuid_link_entity_info_alter(&$entity_info) {
// The username should be the label for users.
$entity_info['user']['entity keys']['label'] = 'name';
}
/**
* Post render callback. Load javascript files and set module settings.
*/
function uuid_link_form_post_render($content, $element) {
static $added;
if (empty($added) && ($js = drupal_add_js()) && isset($js['settings']['data'])) {
$settings = call_user_func_array('array_merge_recursive', $js['settings']['data']);
if (isset($settings['ckeditor']) || isset($settings['wysiwyg']['configs']['ckeditor'])) {
// Pre-load all UUID titles.
preg_match_all('/\\[uuid-link:(.*?)\\]/', $content, $matches);
$tokens = array_unique($matches[1]);
$uuids = array();
foreach ($tokens as $token) {
list($entity_type, $uuid) = explode(':', $token);
$uuids[$entity_type][$uuid] = $uuid;
}
foreach (array_keys($uuids) as $entity_type) {
$entities = entity_uuid_load($entity_type, $uuids[$entity_type]);
foreach ($entities as $entity_id => $entity) {
// If content is language specific show language code.
if (!empty($entity->language) && $entity->language != LANGUAGE_NONE) {
$uuids[$entity_type][$entity->uuid] = t('[@language] @label', array(
'@language' => $entity->language,
'@label' => entity_label($type, $entity),
));
}
else {
$uuids[$entity_type][$entity->uuid] = check_plain(entity_label($entity_type, $entity));
}
}
}
$added = TRUE;
drupal_add_js('misc/autocomplete.js');
$settings = array(
'autocomplete_path' => url('uuid-link/autocomplete'),
'type_name' => uuid_link_get_link_type_name(),
'uuids' => $uuids,
);
drupal_add_js(array(
'uuid_link' => $settings,
), 'setting');
}
}
return $content;
}
/**
* Get a list of available link types. In this case, a list of entity types.
*/
function uuid_link_get_link_type_name() {
$types = array();
$entity_types = entity_get_info();
foreach ($entity_types as $entity_type => $entity_type_info) {
// Only include entities that have a label key set. And that supports UUID.
if (!empty($entity_type_info['entity keys']['label']) && !empty($entity_type_info['entity keys']['uuid'])) {
$types[$entity_type] = $entity_type_info['label'];
}
}
return $types;
}
/**
* Implements hook_token_info().
*/
function uuid_link_token_info() {
$type = array(
'name' => t('UUID Link'),
'description' => t('UUID Link tokens.'),
'needs-data' => 'uuid-link',
);
$entity_types = entity_get_info();
$tokens = array();
foreach ($entity_types as $entity_type => $entity_type_info) {
$tokens[$entity_type] = array(
'name' => t('UUID Link @entity', array(
'@entity' => $entity_type_info['label'],
)),
'description' => t('Translates into an URL to the @entity entity matching the UUID.', array(
'@entity' => $entity_type_info['label'],
)),
'dynamic' => TRUE,
);
}
return array(
'types' => array(
'uuid-link' => $type,
),
'tokens' => array(
'uuid-link' => $tokens,
),
);
}
/**
* Implements hook_tokens().
*/
function uuid_link_tokens($type, $tokens, array $data = array(), array $options = array()) {
if ($type != 'uuid-link') {
return array();
}
static $seen_uuids = array();
static $replacements = array();
$entity_types = entity_get_info();
foreach ($entity_types as $entity_type => $info) {
if (empty($info['entity keys']['label']) || empty($info['entity keys']['uuid'])) {
continue;
}
if ($uuid_link_tokens = token_find_with_prefix($tokens, $entity_type)) {
foreach ($uuid_link_tokens as $uuid => $original) {
// Prevent infinite loops and wasted lookups.
if (isset($replacements[$original])) {
continue;
}
if ($entity_type == 'node') {
// We create a dummy node with only nid and language, as an attempt
// to get a working URL for the node.
$dummy_node = db_select('node', 'n')
->fields('n', array(
'nid',
'language',
))
->condition($info['entity keys']['uuid'], $uuid)
->execute()
->fetchObject();
if (!empty($dummy_node)) {
$replacements[$original] = _uuid_link_entity_url(node_uri($dummy_node), $dummy_node);
continue;
}
}
else {
// Prevent infinite loops for non-nodes. This has the potential to
// result in failed token replacements in the case of circular references.
if (isset($seen_uuids[$uuid])) {
continue;
}
$seen_uuids[$uuid] = TRUE;
$entities = entity_uuid_load($entity_type, array(
$uuid,
));
$entity = array_shift($entities);
// If the entity we just loaded itself has a [uuid-link] token for another entity which
// in turn has a [uuid-link] token for the original entity, (ie. a circular reference)
// then the value will already have been set in the static $replacements[$original], so we
// don't need to load it.
if (isset($replacements[$original])) {
continue;
}
}
if (!empty($entity)) {
$replacements[$original] = uuid_link_entity_url($entity_type, $entity);
}
else {
// Set link URL to this hash, so the link tag can be removed later
// in the filter process function.
$replacements[$original] = '#uuid-link-not-found';
watchdog('uuid_link', 'This content contains a link to content that no longer exists. Please edit the page and remove or change this link to get rid of this notice.');
}
}
}
}
// Return replacements only for the tokens it was asked for.
return array_intersect_key($replacements, array_flip($tokens));
}
/**
* Get URL to an entity.
*
* @param $entity_type
* Entity type.
* @param $entity
* Entity object.
*/
function uuid_link_entity_url($entity_type, $entity) {
switch ($entity_type) {
default:
$uri = entity_uri($entity_type, $entity);
if (is_array($uri)) {
return _uuid_link_entity_url($uri, $entity);
}
case 'file':
return file_create_url($entity->uri);
}
}
/**
* Helper function for getting an language aware url.
*/
function _uuid_link_entity_url($uri, $entity) {
$languages =& drupal_static(__FUNCTION__);
if (empty($languages)) {
$languages = language_list();
}
if (!isset($uri['options']['language']) && !empty($entity->language) && LANGUAGE_NONE !== $entity->language) {
$uri['options']['language'] = $languages[$entity->language];
}
return url($uri['path'], empty($uri['options']) ? array() : $uri['options']);
}
/**
* Implements hook_filter_info().
*/
function uuid_link_filter_info() {
$filters = array();
$filters['uuid_link_filter'] = array(
'title' => t('UUID Link filter'),
'description' => t('Converts links added through UUID Link into actual link to content.'),
'process callback' => 'uuid_link_filter_process',
);
return $filters;
}
/**
* Filter process callback.
*/
function uuid_link_filter_process($text, $filter, $format, $langcode, $cache, $cache_id) {
// Replace uuid-link tokens tokens.
$data = array(
'uuid-link' => array(),
);
$text = token_replace($text, $data);
// Remove tags for links to content that no longer exists. Check the existence
// of the #uuid-link-not-found before doing this expensive job.
if (strpos($text, '#uuid-link-not-found') !== FALSE) {
$dom = filter_dom_load($text);
$xpath = new DOMXPath($dom);
foreach ($xpath
->query('//a[@href="#uuid-link-not-found"]') as $link) {
// Move all link tag content to its parent node just before it.
while ($link
->hasChildNodes()) {
$child = $link
->removeChild($link->firstChild);
$link->parentNode
->insertBefore($child, $link);
}
// Remove the link tag.
$link->parentNode
->removeChild($link);
}
$text = filter_dom_serialize($dom);
}
return $text;
}
/**
* Autocomplete callback for entities.
*/
function uuid_link_autocomplete($type, $string = '') {
$matches = array();
$entity_type = entity_get_info($type);
if (!empty($string) && !empty($entity_type['entity keys']['label'])) {
$label_key = $entity_type['entity keys']['label'];
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', $type)
->propertyCondition($label_key, $string, 'STARTS_WITH')
->propertyOrderBy($label_key)
->range(0, 15);
// Only search for published nodes.
if ($type == 'node') {
$query
->propertyCondition('status', 1);
}
if ($result = $query
->execute()) {
$entities = entity_load($type, array_keys($result[$type]));
$uuids = entity_get_uuid_by_id($type, array_keys($entities));
foreach ($entities as $entity_id => $entity) {
$uuid = $uuids[$entity_id];
// If content is language specific show language code.
if (!empty($entity->language) && $entity->language != LANGUAGE_NONE) {
$label = t('[@language] @label', array(
'@language' => $entity->language,
'@label' => entity_label($type, $entity),
));
}
else {
$label = check_plain(entity_label($type, $entity));
}
$matches[t('@label (@uuid)', array(
'@label' => $label,
'@uuid' => $uuid,
))] = $label;
}
}
}
drupal_json_output($matches);
}
Functions
Name![]() |
Description |
---|---|
uuid_link_autocomplete | Autocomplete callback for entities. |
uuid_link_element_info_alter | Implements hook_element_info_alter(). |
uuid_link_entity_info_alter | Implements hook_entity_info_alter(). |
uuid_link_entity_url | Get URL to an entity. |
uuid_link_filter_info | Implements hook_filter_info(). |
uuid_link_filter_process | Filter process callback. |
uuid_link_form_post_render | Post render callback. Load javascript files and set module settings. |
uuid_link_get_link_type_name | Get a list of available link types. In this case, a list of entity types. |
uuid_link_menu | Implements hook_menu(). |
uuid_link_permission | Implements hook_permission(). |
uuid_link_tokens | Implements hook_tokens(). |
uuid_link_token_info | Implements hook_token_info(). |
uuid_link_wysiwyg_plugin | Implements hook_wysiwyg_plugin(). |
_uuid_link_entity_url | Helper function for getting an language aware url. |