symlink-8.x-1.x-dev/symlink.module
symlink.module
<?php
/**
* @file
* Contains symlink.module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
/**
* Implements hook_help().
*/
function symlink_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the symlink module.
case 'help.page.symlink':
$output = '<h3>' . t('About symlink') . '</h3>';
$output .= '<p>' . t("Symlinks are special nodes that will point to
target nodes and display the content of the target node when they are
displayed. This will let you have a better experience when you need to
add a node in multiple locations of the menu try while maintaining a
proper trail/breadcrumb structure.") . '</p>';
return $output;
default:
return '';
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function symlink_form_node_symlink_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$symlink = $_REQUEST['symlink'] ?? '';
if (!$symlink) {
return;
}
$node = _symlink_get_target_node($symlink);
if (!$node) {
return;
}
$form['field_symlink']['widget'][0]['value']['#default_value'] = empty($node->get('nid')->value) ? '' : "node/{$node->id()}";
$form['title']['widget'][0]['value']['#default_value'] = $node->get('title')->getString() ?? '';
}
/**
* Implements hook_ENTITY_TYPE_view().
*/
function symlink_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if (
(method_exists($entity, 'getType'))
&& (method_exists($entity, 'get'))
&& ('symlink' != $entity->getType())
) {
return;
}
$symlink = $entity->get('field_symlink')->getString();
$node = _symlink_get_target_node($symlink);
if (!$node) {
return;
}
$output = \Drupal::entityTypeManager()
->getViewBuilder('node')
->view($node, $view_mode);
// Remove the redundant node title.
$output['#node']->setTitle("");
$build['symlink_target_content'] = [
'#markup' => \Drupal::service('renderer')->render($output),
];
}
/**
* Helper function to find the node referenced by the symlink.
*
* @param string $symlink
* The node's canonical id.
*
* @return mixed|NULL $node
* The target node object or NULL if not found.
*/
function _symlink_get_target_node(string $symlink) {
$exploded_symlink = explode('/', $symlink, 2);
if (count($exploded_symlink) != 2) {
// TODO: Log something here
return NULL;
}
[$entity_type_id, $nid] = $exploded_symlink;
$nid = (int) $nid;
if ($nid) {
try {
$storage = Drupal::entityTypeManager()->getStorage($entity_type_id);
} catch (Exception $e) {
\Drupal::logger('symlink')->error($e->getMessage(), ['entity_type_id' => $entity_type_id]);
return NULL;
}
$node = $storage->load($nid);
if (
(method_exists($node, 'getType'))
&& (method_exists($node, 'get'))
&& ('symlink' == $node->getType())
) {
$existing_symlink = $node->get('field_symlink')->getString();
if ($existing_symlink) {
// If the target of a symlink is another symlink, then dig deeper until
// a valid node target is found.
return _symlink_get_target_node($existing_symlink);
}
else {
return NULL;
}
}
return $node;
}
else {
return NULL;
}
}
