You are here

onlyone.module in Allow a content type only once (Only One) 8

Same filename and directory in other branches
  1. 7 onlyone.module

Contains onlyone.module.

File

onlyone.module
View source
<?php

/**
 * @file
 * Contains onlyone.module.
 */
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Core\Link;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\Markup;

/**
 * Implements hook_help().
 */
function onlyone_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help.
    case 'help.page.onlyone':

      // The route onlyone.add_page exists or not?
      if (\Drupal::service('config.factory')
        ->get('onlyone.settings')
        ->get('onlyone_new_menu_entry')) {

        // Creating the link.
        $onlyone_add_page_link = Link::fromTextAndUrl(t('Add content (Only One)'), Url::fromRoute('onlyone.add_page'))
          ->toString();
        $onlyone_add_page = t('@link page', [
          '@link' => $onlyone_add_page_link,
        ]);
      }
      else {

        // As the route doesn't exists we use a string.
        $onlyone_add_page = t('<em>Add content (Only One)</em> page (onlyone/add)');
      }

      // Array with routes to replace.
      $routes = [
        ':settings-page' => Url::fromRoute('onlyone.admin_settings')
          ->toString(),
        ':content' => Url::fromRoute('system.admin_content')
          ->toString(),
        '@onlyone_add_page' => $onlyone_add_page,
        ':add-content' => Url::fromRoute('node.add_page')
          ->toString(),
      ];

      // Getting the help link for the admin_toolbar module.
      $admin_toolbar_page = \Drupal::service('onlyone.module_handler')
        ->getModuleHelpPageLink('admin_toolbar', 'Admin Toolbar', TRUE);

      // Getting the help link for the admin_toolbar_tools module.
      $admin_toolbar_tools_page = \Drupal::service('onlyone.module_handler')
        ->getModuleHelpPageLink('admin_toolbar_tools', 'Admin Toolbar Extra Tools', TRUE);

      // Getting the help link for the onlyone_admin_toolbar module.
      $onlyone_admin_toolbar = \Drupal::service('onlyone.module_handler')
        ->getModuleHelpPageLink('onlyone_admin_toolbar', 'Allow a content type only once (Only One) for Admin Toolbar');
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Allow a content type only once (Only One) module allows the creation of Only One content per language in the selected content types for this configuration.') . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Configuring content types') . '</dt>';
      $output .= '<dd>' . t('To configure the content types to allow for Only One content per language, visit the <a href=":config-page">Only One</a> page, in the <em>Available content types for Only One</em> section and <em>check</em> the content types that should have Only One content per language. For this you need the <em>Administer Only One</em> permission.', [
        ':config-page' => Url::fromRoute('onlyone.config_content_types')
          ->toString(),
      ]) . '</dd>';
      $output .= '<dt>' . t('Configuring module settings') . '</dt>';
      $output .= '<dd>' . t('To configure the module settings visit the <a href=":settings-page">Settings</a> page, if you want to have the configured content types in a new menu entry named <em>Add content (Only One)</em> you must check the option <em>Show configured content types in a new menu entry</em>, the new menu link will be available in the <a href=":content">Content</a> page as an action link to the @onlyone_add_page, then the <a href=":add-content">Add content</a> page will show the not configured content types. For this you need the <em>Administer Only One</em> permission.', $routes) . '</dd>';
      $output .= '<dt>' . t('Creating content') . '</dt>';
      $output .= '<dd>' . t('Once you try to <a href=":add-content">Add content</a>, if the chosen content type is configured to have Only One content and it already has one content created in the actual language, you will be redirected to <em>edit</em> the content, otherwise, you will go to create a new one.', [
        ':add-content' => Url::fromRoute('node.add_page')
          ->toString(),
      ]) . '</dd>';
      $output .= '</dl>';
      $output .= '<h3>' . t('Aditionals modules') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . $onlyone_admin_toolbar . '</dt>';
      $output .= '<dd>' . t('Very useful if you use the @admin_toolbar_page module as it handles modifications to the @admin_toolbar_tools_page module menu entries related to the configured content types.', [
        '@admin_toolbar_page' => $admin_toolbar_page,
        '@admin_toolbar_tools_page' => $admin_toolbar_tools_page,
      ]) . '</dd>';
      $output .= '</dl>';
      return $output;
  }
}

/**
 * Implements hook_menu_local_actions_alter().
 */
function onlyone_menu_local_actions_alter(&$local_actions) {

  // Adding the local actions if the new menu entry option is active.
  if (\Drupal::config('onlyone.settings')
    ->get('onlyone_new_menu_entry')) {
    $local_actions['onlyone.add_page'] = [
      'title' => t('Add content (Only One)'),
      'weight' => -1,
      'route_name' => 'onlyone.add_page',
      'options' => [],
      'appears_on' => [
        'system.admin_content',
      ],
      'class' => 'Drupal\\Core\\Menu\\LocalActionDefault',
    ];
  }
}

/**
 * Implements hook_menu_links_discovered_alter().
 */
function onlyone_menu_links_discovered_alter(&$links) {

  // Adding the menu link if the new menu entry option is active.
  if (\Drupal::config('onlyone.settings')
    ->get('onlyone_new_menu_entry')) {
    $links['onlyone.add_page'] = [
      'title' => t('Add content (Only One)'),
      'route_name' => 'onlyone.add_page',
      'menu_name' => 'admin',
      'parent' => 'system.admin_content',
      'description' => t('Add content page for content types configured to have Only One node per language.'),
    ];
  }
}

/**
 * Implements hook_preprocess_HOOK() for block content add list templates.
 */
function onlyone_preprocess_node_add_list(&$variables) {

  // Getting the route.
  $route = \Drupal::request()->attributes
    ->get('_route');

  // Getting variable to know if we should show the configured content type
  // in a new page.
  $onlyone_new_menu_entry = \Drupal::config('onlyone.settings')
    ->get('onlyone_new_menu_entry');

  // Leaving this code here until this issue will be resolved:
  // https://www.drupal.org/project/drupal/issues/2965718
  // @see https://www.drupal.org/project/onlyone/issues/3029598
  // Creating the message variable.
  if ($route == 'onlyone.add_page') {
    $variables['message'] = t('You have not configured any content type yet, go to the <a href=":config-content-types">Only One page</a> to configure the content types.', [
      ':config-content-types' => Url::fromRoute('onlyone.config_content_types')
        ->toString(),
    ]);
  }
  else {
    if ($onlyone_new_menu_entry) {
      $variables['message'] = t('All the content types are configured to have Only One node. Go to the <a href=":add-onlyone-content-type">Add content (Only One)</a> page to create or edit content.', [
        ':add-onlyone-content-type' => Url::fromRoute('onlyone.add_page')
          ->toString(),
      ]);
    }
    else {
      $variables['message'] = t('You have not created any content types yet. Go to the <a href=":add-content-type">Add content type</a> page to create content types.', [
        ':add-content-type' => Url::fromRoute('node.type_add')
          ->toString(),
      ]);
    }
  }

  // Getting the configured content types.
  $onlyone_content_types = \Drupal::config('onlyone.settings')
    ->get('onlyone_node_types');

  // Modifying the contet types information if needed.
  foreach ($onlyone_content_types as $content_type_machine_name) {

    // If the user don't have permission to create the content type even if it
    // is configured to have only one node the content type will not exists
    // in the render array.
    // See: https://www.drupal.org/project/onlyone/issues/3028525 .
    if (empty($variables['content'][$content_type_machine_name])) {
      continue;
    }

    // Getting help from the community to solve this part, see:
    // https://drupal.stackexchange.com/q/244030/28275 .
    // We need to modify the links?
    if (!($onlyone_new_menu_entry xor $route == 'onlyone.add_page')) {

      // Getting the content type.
      $content_type = $variables['content'][$content_type_machine_name];

      // Checking if exists nodes created for the content type.
      if (\Drupal::service('onlyone')
        ->existsNodesContentType($content_type_machine_name)) {

        // Assigning the new name.
        $new_name = t('@content_type_name (Edit)', [
          '@content_type_name' => $content_type
            ->get('name'),
        ]);
        $variables['content'][$content_type_machine_name]
          ->set('name', $new_name);

        // Changing the value in the original template, because all the themes
        // dont' use the same variables, see the seven theme as example.
        // @see template_preprocess_block_content_add_list().
        $variables['types'][$content_type_machine_name]['title'] = $new_name;
      }
      $original_description = empty($content_type
        ->getDescription()) ? '' : rtrim($content_type
        ->getDescription(), '.') . '.';
      $original_description_markup = Markup::create($original_description);
      $description = t('@description <strong>Only a single node can be created and edited</strong>.', [
        '@description' => $original_description_markup,
      ]);

      // Changing the value in the content type.
      $variables['content'][$content_type_machine_name]
        ->set('description', $description);

      // Changing the value in the original template, because all the themes
      // dont' use the same variables, see the seven theme as example.
      // @see template_preprocess_block_content_add_list().
      $variables['types'][$content_type_machine_name]['description'] = $description;
    }
    else {

      // We need to delete the links.
      unset($variables['content'][$content_type_machine_name]);
      unset($variables['types'][$content_type_machine_name]);
    }
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter() for node_form.
 */
function onlyone_form_node_form_alter(&$form, FormStateInterface &$form_state, $form_id) {

  // Getting the configured content types.
  $onlyone_content_types = \Drupal::config('onlyone.settings')
    ->get('onlyone_node_types');
  $onlyone_redirect = \Drupal::config('onlyone.settings')
    ->get('onlyone_redirect');

  // Getting the node.
  $node = $form_state
    ->getFormObject()
    ->getEntity();

  // Verifying if the new node should by onlyone and if we are trying to create
  // a new node.
  if (isset($onlyone_content_types) && in_array($node
    ->getType(), $onlyone_content_types) && $node
    ->isNew()) {

    // If we have one node, then redirect to the edit page.
    $nid = \Drupal::service('onlyone')
      ->existsNodesContentType($node
      ->getType());
    if ($nid) {

      // Creating the url.
      if ($onlyone_redirect) {
        $route = 'entity.node.edit_form';
      }
      else {
        $route = 'entity.node.canonical';
      }
      $url = Url::fromRoute($route, [
        'node' => $nid,
      ])
        ->toString();

      // Redirecting to edit the only one node for this content type.
      $response = new RedirectResponse($url);
      $response
        ->send();
    }
  }
}

/**
 * Implements hook_node_type_delete().
 */
function onlyone_node_type_delete(EntityInterface $node) {

  // Getting the content type machine name.
  $content_type = $node
    ->id();

  // Deleting the value from the config.
  \Drupal::service('onlyone')
    ->deleteContentTypeConfig($content_type);
}

/**
 * Implements hook_entity_type_alter().
 */
function onlyone_entity_type_alter(array &$entity_types) {

  // Adding the constraint. Here is not possible to check specific content type.
  // @see https://drupal.stackexchange.com/q/208283/28275
  if (isset($entity_types['node'])) {
    $entity_types['node']
      ->addConstraint('OnlyOne');
  }
}