rocketship_core-8.x-2.0-alpha11/rocketship_core.module

rocketship_core.module
<?php

/**
 * @file
 * Main module file.
 */

use Drupal\block\Entity\Block;
use Drupal\Component\Utility\Random;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Url;
use Drupal\menu_link_content\MenuLinkContentInterface;
use Drupal\path_alias\PathAliasInterface;
use Drupal\rocketship_core\Event\PathAliasUpdateEvent;
use Drupal\user\Entity\Role;
use Symfony\Component\Yaml\Yaml;

/**
 * Implements hook_token_info().
 */
function rocketship_core_token_info() {
  // Add a token for the alias of the parent menu link.
  $info['tokens']['menu-link']['parent-alias'] = [
    'name' => t('Menu parent: alias'),
    'description' => t('URL alias of the menu parent.'),
  ];
  $info['tokens']['current-page']['paged-url'] = [
    'name' => t('Paged URL'),
    'description' => t('The URL of the current page including the page query parameter.'),
    'type' => 'url',
  ];
  return $info;
}

/**
 * Implements hook_tokens().
 */
function rocketship_core_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  $replacements = [];
  $language_manager = \Drupal::languageManager();
  $url_options = ['absolute' => TRUE];
  if (isset($options['langcode'])) {
    $url_options['language'] = $language_manager->getLanguage($options['langcode']);
  }

  if ($type == 'menu-link' && !empty($data['menu-link'])) {
    $link = $data['menu-link'];
    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');

    if ($link instanceof MenuLinkContentInterface) {
      $link = $menu_link_manager->createInstance($link->getPluginId());
    }
    foreach ($tokens as $name => $original) {
      switch ($name) {
        case 'parent-alias':
          if ($link->getParent() && $parent = $menu_link_manager->createInstance($link->getParent())) {
            $alias_manager = \Drupal::service('path_alias.manager');
            $url = $parent->getUrlObject();
            if (!$url->isExternal()) {
              $path = '/' . $url->getInternalPath();
              $replacements[$original] = $alias_manager->getAliasByPath($path);
            }
          }
          break;
      }
    }
  }

  // Current page tokens.
  if ($type == 'current-page') {
    $request = \Drupal::request();
    foreach ($tokens as $name => $original) {
      switch ($name) {
        // Returns the current page url + the page query parameter if present.
        case 'paged-url':
          $page = $request->query->get('page', NULL);
          if ($page) {
            $url_options['query']['page'] = $page;
          }
          $bubbleable_metadata->addCacheContexts(['url']);
          try {
            $url = Url::createFromRequest($request)->setOptions($url_options);
          }
          catch (\Exception $e) {
            // Url::createFromRequest() can fail, e.g. on 404 pages.
            // Fall back and try again with Url::fromUserInput().
            try {
              $url = Url::fromUserInput($request->getPathInfo(), $url_options);
            }
            catch (\Exception $e) {
              // Instantiation would fail again on malformed urls.
            }
          }
          if (isset($url)) {
            $replacements[$original] = $url->toString();
          }
          break;
      }
    }
  }

  return $replacements;
}

/**
 * Implements hook_ENTITY_TYPE_update() for 'path_alias'.
 */
function rocketship_core_path_alias_update(PathAliasInterface $path_alias) {
  /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
  $event_dispatcher = \Drupal::service('event_dispatcher');

  // Dispatch the path alias update event.
  $event = new PathAliasUpdateEvent($path_alias);
  $event_dispatcher->dispatch(PathAliasUpdateEvent::PATH_ALIAS_UPDATE, $event);
}

/**
 * Implements hook_BASE_FORM_ID_alter().
 *
 * If the field_header_paragraph is present, and that node is set as the
 * frontpage, hide the header paragraph field.
 */
function rocketship_core_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (isset($form['field_header_paragraph'])) {
    /** @var \Drupal\Core\Entity\EntityForm $form_object */
    $form_object = $form_state->getFormObject();
    /** @var \Drupal\node\NodeInterface $node */
    $node = $form_object->getEntity();
    if ($node->isNew()) {
      return;
    }
    $front = \Drupal::configFactory()->get('system.site')->get('page.front');
    if ("/node/{$node->id()}" == $front) {
      // Hide the paragraph header field
      // $form['field_header_paragraph']['#access'] = FALSE;
      // Unset it, #access => FALSE triggers ImageWidget::validateRequiredFields
      // for some godforsaken reason.
      unset($form['field_header_paragraph']);
    }
  }
}

/**
 * Implements hook_form_alter().
 *
 * We're not using the language selector, instead we're just making it clear
 * to the user in what language they're working in.
 */
function rocketship_core_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Only on admin pages and for logged in users.
  if (!\Drupal::service('router.admin_context')->isAdminRoute()
    || !\Drupal::currentUser()->isAuthenticated()) {
    return;
  }

  $object = $form_state->getFormObject();
  if ($object instanceof ContentEntityFormInterface) {
    $entity = $object->getEntity();
    if ($entity) {
      $language = $entity->language()->getName();

      $text = t('Creating @entity_type in @language', [
        '@language' => $language,
        '@entity_type' => $entity->getEntityType()->getLabel(),
      ]);
      if (!$entity->isNew()) {
        $text = t('Editing @language translation', ['@language' => $language]);
      }
      if ($entity instanceof TranslatableInterface) {
        if ($entity->isNewTranslation() && !$entity->isNew()) {
          $text = t('Adding @language translation', ['@language' => $language]);
        }
      }

      $form['rocketship_core_language_info'] = [
        '#weight' => -9999,
        '#markup' => "<h4>$text</h4>",
      ];
    }
  }
}

/**
 * Implements hook_theme().
 */
function rocketship_core_theme() {
  $return = [
    'idt_widget' => [
      'render element' => 'element',
      'file' => 'rocketship_core.field.inc',
    ],
    'label_value_list_item' => [
      'variables' => ['label' => NULL, 'value' => NULL, 'promoted' => FALSE],
    ],
    'title_description_list_item' => [
      'variables' => [
        'title' => NULL,
        'description' => NULL,
        'wrapper' => NULL,
      ],
    ],
  ];

  return $return;
}

/**
 * Implements hook_theme_registry_alter().
 */
function rocketship_core_theme_registry_alter(&$theme_registry) {
  $layouts = \Drupal::service('plugin.manager.core.layout')->getDefinitions();

  $layout_theme_hooks = [];
  /** @var \Drupal\Core\Layout\LayoutDefinition $info */
  foreach ($layouts as $info) {
    if ($info->getCategory() == 'Rocketship Layouts - Display Suite') {
      $layout_theme_hooks[$info->getThemeHook()] = 'layout';
    }

    if ($info->getCategory() == 'Rocketship Layouts - Panels') {
      $layout_theme_hooks[$info->getThemeHook()] = 'layout';
    }
  }

  // Only add preprocess functions if entity exposes theme function, and this
  // layout is using the Display Suite layout class.
  foreach ($theme_registry as $theme_hook => $info) {
    if (array_key_exists($theme_hook, $layout_theme_hooks) || (!empty($info['base hook']) && array_key_exists($info['base hook'], $layout_theme_hooks))) {

      // @todo Remove once https://www.drupal.org/node/2861840 is resolved.
      if (!in_array('template_preprocess_layout', $theme_registry[$theme_hook]['preprocess functions'])) {
        $theme_registry[$theme_hook]['preprocess functions'][] = 'template_preprocess_layout';
      }
    }
  }

  // ------------------------------------------------------------------------
  // Workaround to get theme suggestions working for templates using the
  // the Display Suite class. It's borderline insane, but gets the job done.
  //
  // Note that this currently only works for Twig, but I assume, there isn't
  // any other engine out there yet for Drupal 8.
  //
  // Code based on drupal_find_theme_templates().
  //
  // @see
  // - https://www.drupal.org/node/2862683 (core queue)
  // - https://www.drupal.org/node/2802429 (DS queue)
  // (and maybe others)
  // ------------------------------------------------------------------------.
  // Merge layout and field hooks.
  $all_ds_theme_hooks = $layout_theme_hooks;

  $engine = \Drupal::theme()->getActiveTheme()->getEngine();
  if ($engine == 'twig') {

    $extension = '.html.twig';
    $theme_path = \Drupal::theme()->getActiveTheme()->getPath();

    // Escape the periods in the extension.
    $regex = '/' . str_replace('.', '\.', $extension) . '$/';
    // Get a listing of all template files in the path to search.
    $files = \Drupal::service('file_system')
      ->scanDirectory($theme_path, $regex, ['key' => 'filename']);
    $patterns = array_keys($files);
    $implementations = [];

    foreach ($all_ds_theme_hooks as $hook => $base_hook) {

      // Ignored if not registered (which would be weird).
      if (!isset($theme_registry[$hook])) {
        continue;
      }

      $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
      if (!empty($pattern)) {
        // Transform _ in pattern to - to match file naming scheme
        // for the purposes of searching.
        $pattern = strtr($pattern, '_', '-');

        $matches = preg_grep('/^' . $pattern . '/', $patterns);
        if ($matches) {
          foreach ($matches as $match) {
            $file = $match;
            // Remove the extension from the filename.
            $file = str_replace($extension, '', $file);
            // Put the underscores back in for the hook name and register this
            // pattern.
            $info = $theme_registry[$hook];
            $arg_name = isset($info['variables']) ? 'variables' : 'render element';
            $new_hook = strtr($file, '-', '_');
            $implementations[$new_hook] = [
              'template' => $file,
              'path' => dirname($files[$match]->uri),
              $arg_name => $info[$arg_name],
              'base hook' => $base_hook,
              'type' => 'theme_engine',
              'theme path' => $theme_path,
            ];
            if (isset($theme_registry[$hook]['preprocess functions'])) {
              $implementations[$new_hook]['preprocess functions'] = $theme_registry[$hook]['preprocess functions'];
            }
          }
        }
      }
    }

    if (!empty($implementations)) {
      $theme_registry += $implementations;
    }
  }

  // ------------------------------------------------------------------------
  // End of workaround, hopefully we can kill this one day.
  // ------------------------------------------------------------------------.
}

/**
 * implements hook_blazy_alter().
 */
function rocketship_core_blazy_alter(array &$build, array $settings = []) {
  // This will trigger when you use the Media Blazy formatter on a media reference field.
  // So, for example, on the Paragraph or Node level. This will do nothing if
  // you use the normal Blazy formatter on an Image field on the Media entity
  // level.

  // Only do something if media_switch set to content and it's a media item.
  if (!empty($settings['media_switch']) && $settings['media_switch'] == 'content' && isset($settings['media_source'])) {
    // Load the entity
    $entity = Drupal::entityTypeManager()
      ->getStorage($settings['entity_type_id'])
      ->load($settings['entity_id']);
    if ($entity) {
      // Get highest parent. Basically, if we loaded a Paragraph it'll
      // wind up at a non-Paragraph entity. If it's already a non-Paragraph
      // entity nothing will happen.
      $entity = Rocketship::getHighestLevelParentEntity($entity);
      /** @var \Drupal\Core\Entity\EntityRepositoryInterface $repo */
      $repo = \Drupal::service('entity.repository');
      $entity = $repo->getTranslationFromContext($entity);
      // Now fill that in as the content_url, Blazy will handle the rest.
      $build['#build']['settings']['content_url'] = $entity->toUrl();
    }
  }
}

/**
 * Class Rocketship.
 *
 * @package Drupal\rocketship_core
 */
class Rocketship {

  public static function getHighestLevelParentEntity(EntityInterface $entity) {
    if (method_exists($entity, 'getParentEntity')) {
      $parent = $entity->getParentEntity();
      if ($parent) {
        return static::getHighestLevelParentEntity($parent);
      }
      // Empty parent, assume this level is fine.
      return $entity;
    }
    // Already highest level as far as we can tell.
    return $entity;
  }

  /**
   * Update roles for a modules for Rocketship.
   *
   * If a module has permissions folder with .yml files
   * named ROLE.yml with a permissions key and then a list
   * of permissions, this function will update those roles
   * with those permissions.
   *
   * @param string $module
   *   Module name.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public static function updateRolePermissionsForModule($module) {

    $path = \Drupal::service('module_handler')
        ->getModule($module)
        ->getPath() . '/permissions';

    /** @var \Drupal\user\RoleInterface[] $roles */
    $roles = Role::loadMultiple();

    foreach ($roles as $role) {
      $file_path = $path . '/' . $role->id() . '.yml';
      if (is_file($file_path)) {
        $file_contents = file_get_contents($file_path);
        $file = (array) Yaml::parse($file_contents);

        foreach ($file['permissions'] as $permission) {
          $role->grantPermission($permission);
        }
        $role->save();
      }
    }
  }

  /**
   * Get module installer service.
   *
   * @return \Drupal\Core\Extension\ModuleInstallerInterface
   *   Service.
   */
  public static function getModuleInstaller() {
    return \Drupal::service('module_installer');
  }

  /**
   * Get UUID Generator service.
   *
   * @return \Drupal\Component\Uuid\UuidInterface
   *   Service.
   */
  public static function getUuidGenerator() {
    return \Drupal::service('uuid');
  }

  /**
   * Helper function to place blocks in a region.
   *
   * @param string $plugin_id
   *   Block plugin ID.
   * @param array $settings
   *   Block settings.
   *
   * @return bool|\Drupal\block\BlockInterface
   *   FALSE on failure or the Block that was just placed.
   */
  public static function placeBlock($plugin_id, array $settings = []) {
    // Set theme fallback.
    $theme = isset($settings['theme']) ? $settings['theme'] : \Drupal::configFactory()
      ->get('system.theme')
      ->get('default');

    // Generate ID.
    $id = $theme . '_' . str_replace([':', '-'], '_', $plugin_id);
    if (strlen($id) > 64) {
      // Fallback if max length exceeded.
      $id = (new Random())->name(8);
    }

    // Make sure region is valid.
    $regions = system_region_list($theme);
    $region = isset($settings['region']) ? $settings['region'] : system_default_region($theme);
    if (!isset($regions[$region])) {
      $region = system_default_region($theme);
    }

    // Fill in defaults.
    $settings += [
      'plugin' => $plugin_id,
      'region' => $region,
      'id' => $id,
      'theme' => $theme,
      'label' => '',
      'visibility' => [],
      'weight' => 0,
    ];
    $values = [];

    $keys = [
      'region',
      'id',
      'theme',
      'plugin',
      'weight',
      'visibility',
    ];
    foreach ($keys as $key) {
      $values[$key] = $settings[$key];
      // Remove extra values that do not belong in the settings array.
      unset($settings[$key]);
    }
    foreach ($values['visibility'] as $id => $visibility) {
      $values['visibility'][$id]['id'] = $id;
    }
    $values['settings'] = $settings;
    $block = Block::create($values);
    try {
      $block->save();

      return $block;
    }
    catch (\Exception $e) {
      \Drupal::logger('Rocketship')->error($e->getMessage());

      return FALSE;
    }
  }

  /**
   * Render a block.
   *
   * @param string $plugin_id
   *   Plugin ID.
   * @param array $config
   *   Config array.
   *
   * @return array
   *   Renderable array.
   *
   * @see https://drupal.stackexchange.com/questions/171686/how-can-i-programmatically-display-a-block
   */
  public static function renderPluginBlock($plugin_id, array $config = []) {
    $block_manager = \Drupal::service('plugin.manager.block');
    $plugin_block = $block_manager->createInstance($plugin_id, $config);
    // Some blocks might implement access check.
    $access_result = $plugin_block->access(\Drupal::currentUser());
    // Return empty render array if user doesn't have access.
    // $access_result can be boolean or an AccessResult class.
    if (is_object($access_result) && $access_result->isForbidden() || is_bool($access_result) && !$access_result) {
      // You might need to add some cache tags/contexts.
      return [];
    }
    $render = $plugin_block->build();
    // In some cases, you need to add the cache tags/context depending on
    // the block implemention. As it's possible to add the cache tags and
    // contexts in the render method and in ::getCacheTags and
    // ::getCacheContexts methods.
    return $render;
  }

  /**
   * Hides the breadcrumb and title block on detail pages for the given CT.
   *
   * @param string $theme
   *   Theme name.
   * @param string $contentType
   *   Content type name.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public static function hideBreadcrumbAndTitleBlockOnContentType($theme, $contentType) {

    $blocks = [
      "{$theme}_breadcrumbs",
      "{$theme}_page_title",
    ];

    foreach ($blocks as $config_name) {
      /** @var \Drupal\block\BlockInterface $block */
      $block = Block::load($config_name);
      if ($block) {
        $visibility = $block->getVisibility();
        $visibility['entity_bundle:node']['bundles'][$contentType] = $contentType;
        $visibility['entity_bundle:node']['negate'] = TRUE;
        $visibility['entity_bundle:node']['context_mapping']['node'] = '@node.node_route_context:node';
        $block->setVisibilityConfig('entity_bundle:node', $visibility['entity_bundle:node']);
        $block->save();
      }
    }
  }

  /**
   * @param string $entityType
   *   Entity type name.
   * @param string $bundle
   *   Bundle name.
   *
   * @deprecated
   *
   * Ensure content types have the translation tables.
   *
   * Creating CTs with config imports doesn't trigger translation table updates.
   *
   * @see https://www.drupal.org/project/drupal/issues/2599228
   *
   * @todo: rework applyUpdates, because it's going away in 8.7
   * This entire thing shouldn't be needed once 8.8 hits.
   *
   * The patch to fix translations has hit early, it's in 8.7 so this
   * method is no longer required. Marking as deprecated.
   */
  public static function fixTranslationConfigImportIssues($entityType, $bundle) {

  }

}

if (!function_exists("array_key_last")) {
  function array_key_last($array) {
    if (!is_array($array) || empty($array)) {
      return NULL;
    }

    return array_keys($array)[count($array) - 1];
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc