Как связать свою сущность с Pathauto в Drupal

Тема сегодняшнего урока это интеграция сущности с модулем Pathauto. Чтобы решить поставленную задачу, необходимо, чтобы сущность поддерживала токены. Как это сделать читайте в моем предыдущем уроке поддержка токенов для своей сущности в Drupal.

И так, переходим от слов к делу, скачиваем модуль Pathauto, открываем product.info и добавляем зависимость:

dependencies[] = pathauto

Зависимость добавили, теперь открываем product.module и имплементируем хук hook_pathauto():

/**
 * Implements hook_pathauto().
 */
function product_pathauto($op) {
  if ($op == 'settings') {
    $settings = array(
      'module' => 'product', // Название модуля.
      'groupheader' => t('Product Paths'), // Заголовок группы, который отображается на странице шаблонов pathauto.
      'patterndescr' => t('Default path pattern (applies to all products with blank patterns below)'), // Описание группы.
      'patterndefault' => 'product/[product:title]', // Шаблон, который используется по умолчанию.
      'token_type' => 'product', // Тип токена.
      'patternitems' => array(), // В этом массиве хранятся настройки для кажого бандла, их мы добавим ниже.
      'batch_update_callback' => 'product_bulk_update_batch_process', // Функция, которая будет срабатывать при массиовом обновлении альясов.
      'batch_file' => drupal_get_path('module', 'product') . '/product.pathauto.inc', // Путь к файлу, в котором хранится функция.
    );
    
    // Получаем информацию о нашей сущности и делаем возможность настроить шаблон для каждого бандла в отдельности.
    $entity_info = entity_get_info('product');
    foreach ($entity_info['bundles'] as $bundle_id => $bundle) {
      $settings['patternitems'][$bundle_id] = t('Pattern for all @label paths', array('@label' => $bundle['label']));
    }

    return (object) $settings;
  }
}

Далее имплементируем хук hook_path_alias_types(), для того, чтобы в админке стала доступна функция массового удаления альясов этого типа:

/**
 * Implements hook_path_alias_types().
 */
function product_path_alias_types() {
  $objects['product/'] = t('Products');
  return $objects;
}

Теперь напишем служебные функции для сохранения и обновления альясов:

/**
 * Update the URL aliases for an individual product.
 *
 * @param $product
 *   A product object.
 * @param $op
 *   Operation being performed on the product ('insert', 'update' or 'bulkupdate').
 */
function _product_update_alias($product, $op) {
  // Получаем uri продукта.
  $uri = product_uri($product);
  $product_wrapper = entity_metadata_wrapper('product', $product);

  // Получаем машинное имя бандла.
  $bundle = $product_wrapper->getBundle();

  // Создаем альяс.
  module_load_include('inc', 'pathauto');
  pathauto_create_alias('product', $op, $uri['path'], array('product' => $product), $bundle);
}

/**
 * Update the URL aliases for multiple products.
 *
 * @param $ids
 *   An array of product IDs.
 * @param $op
 *   Operation being performed on the products ('insert', 'update' or
 *   'bulkupdate').
 */
function _product_update_alias_multiple($ids, $op) {
  // Загружаем продукты.
  $products = product_load_multiple($ids);
  foreach ($products as $product) {
    // Обновляем альясы.
    _product_update_alias($product, $op);
  }
  
  // Выводим сообщение о том, сколько альясов было обновлено.
  drupal_set_message(format_plural(count($ids), 'Updated URL alias for 1 product.', 'Updated URL aliases for @count products.'));
}

Служебные функции написали, теперь имплементируем хук hook_entity_insert() для создания нового альяса:

/**
 * Implements hook_entity_insert().
 */
function product_entity_insert($entity, $type) {
  if ($type == 'product') {
    _product_update_alias($entity, 'insert');
  }
}

Далее имплементируем хук hook_entity_update() для обновления альяса:

/**
 * Implements hook_entity_update().
 */
function product_entity_update($entity, $type) {
  if ($type == 'product') {
    _product_update_alias($entity, 'update');
  }
}

Теперь имплементируем хук hook_entity_delete() для удаления альса вместе с удаляемой сущностью:

/**
 * Implements hook_entity_delete().
 */
function product_entity_delete($entity, $type) {
  if ($type == 'product') {
    $uri = product_uri($entity);
    pathauto_entity_path_delete_all('product', $entity, $uri['path']);
  }
}

Осталось написать массовое обновление альясов. Создаем файл product.pathauto.inc, его содержимое:

<?php

/**
 * @file
 * Pathauto integration for Product module.
 *
 * @ingroup pathauto
 */

/**
 * Batch processing callback; Generate aliases for products.
 */
function product_bulk_update_batch_process(&$context) {
  if (!isset($context['sandbox']['current'])) {
    $context['sandbox']['count'] = 0;
    $context['sandbox']['current'] = 0;
  }

  $query = db_select('product', 'p');
  $query->leftJoin('url_alias', 'ua', "CONCAT('product/', p.id) = ua.source");
  $query->addField('p', 'id');
  $query->isNull('ua.source');
  $query->condition('p.id', $context['sandbox']['current'], '>');
  $query->orderBy('p.id');
  $query->addTag('pathauto_bulk_update');
  $query->addMetaData('entity', 'product');

  // Получаем количество продуктов для обработки.
  if (!isset($context['sandbox']['total'])) {
    $context['sandbox']['total'] = $query->countQuery()->execute()->fetchField();

    // Если нет продуктов для обработки, то тут же завершаем работу.
    if (!$context['sandbox']['total']) {
      $context['finished'] = 1;
      return;
    }
  }

  $query->range(0, 25);
  $ids = $query->execute()->fetchCol();

  _product_update_alias_multiple($ids, 'bulkupdate');
  $context['sandbox']['count'] += count($ids);
  $context['sandbox']['current'] = max($ids);
  $context['message'] = t('Updated alias for product @id.', array('@id' => end($ids)));

  if ($context['sandbox']['count'] != $context['sandbox']['total']) {
    $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
  }
}

Настраиваем в админке шаблоны альясов и дело сделано!

Комментарии (0)