date_recur-8.x-2.2/date_recur.install

date_recur.install
<?php

/**
 * @file
 * Install, update and uninstall functions for date_recur module.
 */

declare(strict_types=1);

use Drupal\Core\Database\SchemaObjectExistsException;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Utility\UpdateException;
use Drupal\date_recur\DateRecurOccurrences;
use Drupal\date_recur\Entity\DateRecurInterpreter;
use Drupal\date_recur\Plugin\Field\FieldWidget\DateRecurBasicWidget;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;

/**
 * Implements hook_requirements().
 */
function date_recur_requirements($phase): array {
  $requirements = [];

  if (!class_exists('\RRule\RRule')) {
    $requirements['date_recur_dependencies'] = [
      'title' => t('Date recur'),
      'description' => \t('Date recur has unmet Composer dependencies. Read the <a href="@url">documentation</a> on how to install them.', [
        '@url' => 'https://www.drupal.org/node/2627292',
      ]),
      'severity' => \REQUIREMENT_ERROR,
    ];
  }

  return $requirements;
}

/**
 * Update date recur fields with new column schema for 'rrule' property.
 */
function date_recur_update_8201(&$sandbox): void {
  // The process is:
  // 1. Determine all entity types with date recur fields and load their
  //    definitions.
  // 2. Update the SQL table schema for all relevant tables.
  // 3. Inform Drupal of the expected table schemas.
  // 4. Update Drupal's entity type definitions.
  $fieldType = 'date_recur';
  $schema = \Drupal::database()->schema();
  $entityTypeManager = \Drupal::entityTypeManager();
  $entityFieldManager = \Drupal::service('entity_field.manager');
  $entityFieldMap = $entityFieldManager->getFieldMapByFieldType($fieldType);
  $entityStorageSchemaSql = \Drupal::keyValue('entity.storage_schema.sql');
  /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $lastInstalledSchemaRepository */
  $lastInstalledSchemaRepository = \Drupal::service('entity.last_installed_schema.repository');

  // The new SQL schema for our column.
  $specification = [
    'description' => 'The repeat rule.',
    'type' => 'text',
  ];

  // Iterate over all date_recur fields for all entity types.
  foreach ($entityFieldMap as $entityTypeId => $fields) {
    $entityStorage = $entityTypeManager->getStorage($entityTypeId);
    if (!$entityStorage instanceof SqlEntityStorageInterface) {
      continue;
    }

    $entityType = $entityTypeManager->getDefinition($entityTypeId);
    // Loads definitions for all fields (even non date_recur).
    $entityFieldStorageDefinitions = $entityFieldManager->getFieldStorageDefinitions($entityTypeId);
    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $tableMapping */
    $tableMapping = $entityStorage->getTableMapping($entityFieldStorageDefinitions);

    // Intersect date_recur fields with storage definitions for all fields.
    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fieldDefinitions */
    $fieldDefinitions = array_intersect_key($entityFieldStorageDefinitions, $fields);

    // Iterate over all date_recur field definitions for this entity type.
    foreach ($fieldDefinitions as $fieldDefinition) {
      $fieldName = $fieldDefinition->getName();
      $tables = [];
      $tables[] = $tableMapping->getFieldTableName($fieldName);
      if ($entityType->isRevisionable() && $fieldDefinition->isRevisionable()) {
        $tables[] = $tableMapping->getDedicatedRevisionTableName($fieldDefinition);
      }

      // Field type column names map to real table column names.
      $columns = $tableMapping->getColumnNames($fieldName);
      $rruleColumnName = $columns['rrule'];

      foreach ($tables as $table) {
        // Change the column spec here.
        $schema->changeField($table, $rruleColumnName, $rruleColumnName, $specification);
      }

      // Update the tracked entity table schema.
      $schemaKey = "$entityTypeId.field_schema_data.$fieldName";
      $fieldSchemaData = $entityStorageSchemaSql->get($schemaKey);
      foreach ($fieldSchemaData as $tableName => $fieldSchema) {
        // Type is now 'text'.
        $fieldSchemaData[$tableName]['fields'][$rruleColumnName]['type'] = 'text';
        // Type previously was 'varchar', remove the length portion.
        unset($fieldSchemaData[$tableName]['fields'][$rruleColumnName]['length']);
      }
      $entityStorageSchemaSql->set($schemaKey, $fieldSchemaData);

      // Update cached entity definitions for entity types with of single
      // cardinality base fields.
      if ($tableMapping->allowsSharedTableStorage($fieldDefinition)) {
        $definitions = $lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entityTypeId);
        $definitions[$fieldName] = $fieldDefinition;
        $lastInstalledSchemaRepository->setLastInstalledFieldStorageDefinitions($entityTypeId, $definitions);
      }
    }
  }
}

/**
 * Add a default value for new 'rrule_max_length' setting on date recur fields.
 *
 * Applies to attached fields only.
 */
function date_recur_update_8202(&$sandbox): void {
  $fieldType = 'date_recur';
  $entityTypeManager = \Drupal::entityTypeManager();
  $entityFieldManager = \Drupal::service('entity_field.manager');
  $entityFieldMap = $entityFieldManager->getFieldMapByFieldType($fieldType);

  // Iterate over all date_recur fields for all entity types.
  foreach ($entityFieldMap as $entityTypeId => $fields) {
    $entityStorage = $entityTypeManager->getStorage($entityTypeId);
    if (!$entityStorage instanceof SqlEntityStorageInterface) {
      continue;
    }

    // Loads definitions for all fields (even non date_recur).
    $entityFieldStorageDefinitions = $entityFieldManager->getFieldStorageDefinitions($entityTypeId);

    // Intersect date_recur fields with storage definitions for all fields.
    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fieldDefinitions */
    $fieldDefinitions = array_intersect_key($entityFieldStorageDefinitions, $fields);

    // Iterate over all date_recur field definitions for this entity type.
    foreach ($fieldDefinitions as $fieldDefinition) {
      if ($fieldDefinition instanceof FieldStorageConfig) {
        // Ignore base fields, etc.
        $fieldDefinition->setSetting('rrule_max_length', 256);
        $fieldDefinition->save();
      }
    }
  }
}

/**
 * Checks for invalid time zones in storage.
 */
function date_recur_update_8203(&$sandbox): void {
  $timeZoneList = timezone_identifiers_list();
  $database = \Drupal::database();
  $entityTypeManager = \Drupal::entityTypeManager();
  $entityFieldManager = \Drupal::service('entity_field.manager');
  $entityFieldMap = $entityFieldManager->getFieldMapByFieldType('date_recur');

  // Iterate over all date_recur fields for all entity types.
  foreach ($entityFieldMap as $entityTypeId => $fields) {
    $entityStorage = $entityTypeManager->getStorage($entityTypeId);
    if (!$entityStorage instanceof SqlEntityStorageInterface) {
      continue;
    }

    // Loads definitions for all fields (even non date_recur).
    $entityFieldStorageDefinitions = $entityFieldManager->getFieldStorageDefinitions($entityTypeId);
    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $tableMapping */
    $tableMapping = $entityStorage->getTableMapping($entityFieldStorageDefinitions);

    // Intersect date_recur fields with storage definitions for all fields.
    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fieldDefinitions */
    $fieldDefinitions = array_intersect_key($entityFieldStorageDefinitions, $fields);

    // Iterate over all date_recur field definitions for this entity type.
    foreach ($fieldDefinitions as $fieldDefinition) {
      $fieldName = $fieldDefinition->getName();
      $table = $tableMapping->getFieldTableName($fieldName);

      // Field type column names map to real table column names.
      $columns = $tableMapping->getColumnNames($fieldName);
      $timeZoneColumnName = $columns['timezone'];

      $select = $database->select($table, 'field_table');
      $select->addField('field_table', $timeZoneColumnName);
      $select->distinct();
      $result = $select->execute();
      if (!$result) {
        throw new \Exception('Problem executing query.');
      }
      $allTimeZones = $result->fetchCol($timeZoneColumnName);
      $diff = array_diff($allTimeZones, $timeZoneList);

      if (count($diff)) {
        // This exception prevents further updates from happening until it is
        // resolved.
        throw new UpdateException(sprintf('Invalid time zones found for field `%s` in table `%s`: `%s`. Please resolve these invalid values manually before continuing.', $fieldName, $table, implode(', ', $diff)));
      }
    }
  }
}

/**
 * Update view and form display configurations.
 */
function date_recur_update_8204(&$sandbox): void {
  /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface[] $displays */
  $displays = EntityFormDisplay::loadMultiple();
  foreach ($displays as $display) {
    $components = $display->getComponents();
    foreach ($components as $component => $options) {
      $updated = FALSE;
      $type = $options['type'] ?? NULL;
      if ($type === 'date_recur_default_widget') {
        // Change the ID.
        $options['type'] = 'date_recur_basic_widget';
        // No settings to update.
        $updated = TRUE;
      }

      // Interactive widget did not change ID or settings.
      if ($updated) {
        $display->setComponent($component, $options);
      }
    }
    $display->save();
  }

  /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] $displays */
  $displays = EntityViewDisplay::loadMultiple();
  foreach ($displays as $display) {
    $components = $display->getComponents();
    foreach ($components as $component => $options) {
      $updated = FALSE;
      $type = $options['type'] ?? NULL;
      if ($type === 'date_recur_default_formatter') {
        // Option: show_next. Unchanged.
        // Option: count_per_item. Unchanged.
        // Option: occurrence_format_type. Unchanged.
        // Option: same_end_date_format_type. Unchanged.
        // Change the ID.
        $options['type'] = 'date_recur_basic_formatter';

        // Option: show_rrule. Changed to 'interpreter'.
        if (isset($options['show_rrule'])) {
          unset($options['show_rrule']);
        }

        $updated = TRUE;
      }

      if ($updated) {
        $display->setComponent($component, $options);
      }
    }

    $display->save();
  }
}

/**
 * Add a default interpreter.
 */
function date_recur_update_8205(&$sandbox): void {
  if (DateFormat::load('long') && !DateRecurInterpreter::load('default_interpreter')) {
    $configFactory = \Drupal::configFactory();
    $interpreter = $configFactory->getEditable('date_recur.interpreter.default_interpreter');
    $interpreter->setData([
      'id' => 'default_interpreter',
      'label' => 'Default interpreter',
      'plugin' => 'rl',
      'settings' => [
        'show_start_date' => TRUE,
        'show_until' => TRUE,
        'date_format' => 'long',
        'show_infinite' => TRUE,
      ],
    ]);
    $interpreter->save(TRUE);
  }
}

/**
 * Removes default time zone setting from widgets extending basic widget.
 */
function date_recur_update_8206(&$sandbox): void {
  // Get widgets implementing the same class as basic widget.
  /** @var \Drupal\Core\Field\WidgetPluginManager $fieldWidgetPluginManager */
  $basicWidgetClass = DateRecurBasicWidget::class;
  $basicWidgetDerivativeWidgetIds = [];
  $basicWidgetDerivativeWidgetIds[] = 'date_recur_basic_widget';
  $fieldWidgetPluginManager = \Drupal::service('plugin.manager.field.widget');
  foreach ($fieldWidgetPluginManager->getDefinitions() as $widgetId => $definition) {
    $class = $definition['class'];
    if (class_exists($class) && (new \ReflectionClass($class))->isSubclassOf($basicWidgetClass)) {
      $basicWidgetDerivativeWidgetIds[] = $widgetId;
    }
  }

  // Find form displays using any of the widgets extending basic widget.
  /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface[] $displays */
  $displays = EntityFormDisplay::loadMultiple();
  foreach ($displays as $display) {
    $updated = 0;
    $components = $display->getComponents();
    foreach ($components as $component => $options) {
      $widgetId = $options['type'] ?? NULL;
      if (in_array($widgetId, $basicWidgetDerivativeWidgetIds, TRUE)) {
        // Unset the old setting.
        unset($options['settings']['timezone_override']);
        $updated++;
        $display->setComponent($component, $options);
      }
    }

    if ($updated > 0) {
      $display->save();
    }
  }
}

/**
 * Updates default time zone configuration.
 */
function date_recur_update_8207(&$sandbox): void {
  /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager */
  $entityFieldManager = \Drupal::service('entity_field.manager');
  $entityFieldMap = $entityFieldManager->getFieldMapByFieldType('date_recur');

  // Iterate over all date_recur fields for all entity types.
  /** @var \Drupal\Core\Field\FieldConfigInterface[] $drFields */
  $drFields = [];
  foreach ($entityFieldMap as $entityTypeId => $fields) {
    foreach ($fields as $fieldName => ['bundles' => $bundles]) {
      foreach ($bundles as $bundle) {
        $field = FieldConfig::loadByName($entityTypeId, $bundle, $fieldName);
        if ($field) {
          array_push($drFields, $field);
        }
      }
    }
  }

  foreach ($drFields as $fieldConfig) {
    $defaultValue = $fieldConfig->getDefaultValueLiteral();
    // Skip if the whole value is empty.
    // Don't bother updating install functions, these will be removed.
    if (empty($defaultValue)) {
      continue;
    }

    // Don't bother updating install functions, these will be removed.
    $defaultValue[0]['default_time_zone_source'] = !empty($defaultValue[0]['default_time_zone'])
      ? 'fixed'
      : 'current_user';
    $fieldConfig->setDefaultValue($defaultValue);
    $fieldConfig->save();
  }
}

/**
 * Update date recur occurrence table schemas to add a primary key.
 */
function date_recur_update_8208(&$sandbox): void {
  // The process is:
  // 1. Determine all entity types with date recur fields and load their
  //    definitions.
  // 2. Update the SQL table schema for all relevant tables.
  $fieldType = 'date_recur';
  $schema = \Drupal::database()->schema();
  $entityTypeManager = \Drupal::entityTypeManager();
  $entityFieldManager = \Drupal::service('entity_field.manager');
  $entityFieldMap = $entityFieldManager->getFieldMapByFieldType($fieldType);

  // Iterate over all date_recur fields for all entity types.
  foreach ($entityFieldMap as $entityTypeId => $fields) {
    $entityStorage = $entityTypeManager->getStorage($entityTypeId);
    if (!$entityStorage instanceof SqlEntityStorageInterface) {
      continue;
    }

    $entityType = $entityTypeManager->getDefinition($entityTypeId);
    $primaryKey = [
      $entityType->isRevisionable() ? 'revision_id' : 'entity_id',
      'field_delta',
      'delta',
    ];
    // Loads definitions for all fields (even non date_recur).
    $entityFieldStorageDefinitions = $entityFieldManager->getFieldStorageDefinitions($entityTypeId);

    // Intersect date_recur fields with storage definitions for all fields.
    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fieldDefinitions */
    $fieldDefinitions = array_intersect_key($entityFieldStorageDefinitions, $fields);

    // Iterate over all date_recur field definitions for this entity type.
    foreach ($fieldDefinitions as $fieldDefinition) {
      $tableName = DateRecurOccurrences::getOccurrenceCacheStorageTableName($fieldDefinition);
      try {
        $schema->addPrimaryKey($tableName, $primaryKey);
      }
      catch (SchemaObjectExistsException $e) {
        // Somehow people already have primary keys set, so ignore.
        continue;
      }
    }
  }
}

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

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