contacts_events-8.x-1.x-dev/contacts_events.install
contacts_events.install
<?php
/**
* @file
* Install and update code for the Contacts Events module.
*/
use Drupal\commerce_order\Entity\OrderItemType;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageException;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\entity\BundleFieldDefinition;
use Drupal\search_api\Item\Field;
/**
* Implements hook_install().
*/
function contacts_events_install() {
$fields['creator'] = BundleFieldDefinition::create('entity_reference')
->setName('creator')
->setLabel(t('Creator'))
->setTargetEntityTypeId('commerce_order')
->setTargetBundle('contacts_booking')
->setDescription(t('The user ID of the order creator.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setTranslatable(FALSE)
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE);
$fields['state_log'] = BundleFieldDefinition::create('status_log')
->setName('state_log')
->setLabel(t('State History'))
->setTargetEntityTypeId('commerce_order')
->setTargetBundle('contacts_booking')
->setDescription(t('A log of when the status was changed and by whom.'))
->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
->setSettings([
'source_field' => 'state',
])
->setDisplayConfigurable('view', FALSE)
->setDisplayConfigurable('form', FALSE);
foreach ($fields as $field_name => $field) {
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition($field_name, 'commerce_order', 'contacts_events', $field);
}
/** @var \Drupal\search_api\IndexInterface $index */
$index = \Drupal::entityTypeManager()->getStorage('search_api_index')->load('contacts_index');
if ($index) {
// Create the Booking Manager booking reference field.
$bm_field = new Field($index, 'bm_order_number');
$bm_field->setType('text');
$bm_field->setPropertyPath('ce_bookings_managed:entity:order_number');
$bm_field->setDatasourceId('entity:user');
$bm_field->setLabel('Bookings (manager) » Order » Order number');
$bm_field->setBoost(8);
// Create the Delegate booking reference field.
$delegate_field = new Field($index, 'delegate_order_number');
$delegate_field->setType('text');
$delegate_field->setPropertyPath('ce_bookings_delegate:entity:order_number');
$delegate_field->setDatasourceId('entity:user');
$delegate_field->setLabel('Bookings (delegate) » Order » Order number');
$delegate_field->setBoost(5);
// Add to fields to the index.
$index->addField($bm_field);
$index->addField($delegate_field);
$index->save();
}
}
/**
* Adds the creator field to Booking orders.
*/
function contacts_events_update_8001() {
$field = BundleFieldDefinition::create('entity_reference')
->setLabel(t('Creator'))
->setTargetEntityTypeId('commerce_order')
->setTargetBundle('contacts_booking')
->setDescription(t('The user ID of the order creator.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setTranslatable(FALSE)
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('creator', 'commerce_order', 'contacts_events', $field);
}
/**
* Adds creator field to payments.
*/
function contacts_events_update_8002() {
$field = BaseFieldDefinition::create('entity_reference')
->setName('creator')
->setTargetEntityTypeId('commerce_payment')
->setLabel(new TranslatableMarkup('Creator'))
->setDescription(new TranslatableMarkup('The user ID of the payment creator.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setTranslatable(FALSE)
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', FALSE);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('creator', 'commerce_payment', 'contacts_events', $field);
}
/**
* Adds the link text overrides field.
*/
function contacts_events_update_8003() {
$field = BaseFieldDefinition::create('contacts_events_text_overrides')
->setLabel('Link text overrides')
->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
->setDisplayConfigurable('view', FALSE)
->setDisplayConfigurable('form', TRUE)
->setDisplayOptions('view', [
'region' => 'hidden',
]);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('link_overrides', 'contacts_event', 'contacts_events', $field);
}
/**
* Adds the settings field.
*/
function contacts_events_update_8004() {
$field = BundleFieldDefinition::create('contacts_events_settings')
->setLabel('Settings')
->setDisplayConfigurable('view', FALSE)
->setDisplayOptions('view', ['region' => 'hidden'])
->setDisplayConfigurable('form', FALSE)
->setDisplayOptions('form', ['region' => 'hidden']);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('settings', 'contacts_event', 'contacts_events', $field);
}
/**
* Adds the state log field to Booking orders.
*/
function contacts_events_update_8005() {
$field = BundleFieldDefinition::create('status_log')
->setName('state_log')
->setLabel(t('Status History'))
->setTargetEntityTypeId('commerce_order')
->setTargetBundle('contacts_booking')
->setDescription(t('A log of when the status was changed and by whom.'))
->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
->setSettings([
'source_field' => 'state',
])
->setDisplayConfigurable('view', FALSE)
->setDisplayConfigurable('form', FALSE);
\Drupal::entityDefinitionUpdateManager()
->installFieldStorageDefinition('state_log', 'commerce_order', 'contacts_events', $field);
}
/**
* Install Booking Transfer payment gateway.
*/
function contacts_events_update_8006() {
$config_name = 'commerce_payment.commerce_payment_gateway.booking_transfer';
if (!\Drupal::service('config.storage')->exists($config_name)) {
$config = \Drupal::configFactory()->getEditable($config_name);
$values = [
'uuid' => \Drupal::service('uuid')->generate(),
'langcode' => 'en',
'status' => FALSE,
'dependencies' => [],
'id' => 'booking_transfer',
'label' => 'Booking Transfer',
'weight' => 10,
'plugin' => 'manual',
'configuration' => [
'instructions' => [
'value' => '',
'format' => 'plain_text',
],
'display_label' => 'Booking Transfer',
'mode' => 'n/a',
'payment_method_types' => [
'credit_card',
],
],
'conditions' => [],
'conditionOperator' => 'AND',
];
foreach ($values as $id => $value) {
$config->set($id, $value);
}
$config->save();
}
}
/**
* Add the cut_off_confirmed column to booking window field tables.
*/
function contacts_events_update_8007() {
$schema = \Drupal::database()->schema();
$entity_type_manager = \Drupal::entityTypeManager();
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
$entity_field_manager = \Drupal::service('entity_field.manager');
$entity_field_map = $entity_field_manager->getFieldMapByFieldType('booking_windows');
$entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
$entity_definitions_installed = \Drupal::keyValue('entity.definitions.installed');
foreach ($entity_field_map as $entity_type_id => $field_map) {
$entity_storage = $entity_type_manager->getStorage($entity_type_id);
// Only SQL storage based entities are supported / throw known exception.
if (!($entity_storage instanceof SqlContentEntityStorage)) {
continue;
}
$entity_type = $entity_type_manager->getDefinition($entity_type_id);
$field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
/** @var Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $entity_storage->getTableMapping($field_storage_definitions);
// Only need field storage definitions of booking windows fields.
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition */
foreach (array_intersect_key($field_storage_definitions, $field_map) as $field_storage_definition) {
$field_name = $field_storage_definition->getName();
try {
$table = $table_mapping->getFieldTableName($field_name);
$cut_off_col_name = $table_mapping->getFieldColumnName($field_storage_definition, 'cut_off');
}
catch (SqlContentEntityStorageException $e) {
// Custom storage? Broken site? No matter what, if there is no table
// or column, there's little we can do.
continue;
}
// See if the field has a revision table.
$revision_table = NULL;
if ($entity_type->isRevisionable() && $field_storage_definition->isRevisionable()) {
if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) {
$revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage_definition);
}
elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
$revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
}
}
// Load the installed field schema so that it can be updated.
$schema_key = "$entity_type_id.field_schema_data.$field_name";
$field_schema_data = $entity_storage_schema_sql->get($schema_key);
// Get the existing spec.
$cut_off_spec = [
'description' => 'The paid in full by date.',
'type' => 'varchar',
'length' => 20,
];
// Update the new column.
$schema->changeField($table, $cut_off_col_name, $cut_off_col_name, $cut_off_spec);
if ($revision_table) {
$schema->changeField($revision_table, $cut_off_col_name, $cut_off_col_name, $cut_off_spec);
}
// Update the existing column in the installed field schema.
if ($field_schema_data) {
$field_schema_data[$table]['fields'][$cut_off_col_name] = $cut_off_spec;
$field_schema_data[$table]['fields'][$cut_off_col_name]['not null'] = FALSE;
if ($revision_table) {
$field_schema_data[$revision_table]['fields'][$cut_off_col_name] = $cut_off_spec;
}
$entity_storage_schema_sql->set($schema_key, $field_schema_data);
}
// Get the new column name and spec.
$cut_off_confirmed_col_name = $table_mapping->getFieldColumnName($field_storage_definition, 'cut_off_confirmed');
$cut_off_confirmed_spec = [
'description' => 'The confirmed by date.',
'type' => 'varchar',
'length' => 20,
];
// Add the new column.
$install_spec = $cut_off_confirmed_spec + ['initial_from_field' => $cut_off_col_name];
$schema->addField($table, $cut_off_confirmed_col_name, $install_spec);
if ($revision_table) {
$schema->addField($revision_table, $cut_off_confirmed_col_name, $install_spec);
}
// Add the new column to the installed field schema.
if ($field_schema_data) {
$field_schema_data[$table]['fields'][$cut_off_confirmed_col_name] = $cut_off_confirmed_spec;
$field_schema_data[$table]['fields'][$cut_off_confirmed_col_name]['not null'] = FALSE;
if ($revision_table) {
$field_schema_data[$revision_table]['fields'][$cut_off_confirmed_col_name] = $cut_off_confirmed_spec;
}
$entity_storage_schema_sql->set($schema_key, $field_schema_data);
}
// Update the installed field storage definition.
if ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
$key = "$entity_type_id.field_storage_definitions";
if ($definitions = $entity_definitions_installed->get($key)) {
$definitions[$field_name] = $field_storage_definition;
$entity_definitions_installed->set($key, $definitions);
}
}
}
}
}
/**
* Add missing fields to order item bundles.
*/
function contacts_events_update_8008() {
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
$entity_field_manager = \Drupal::service('entity_field.manager');
/** @var \Drupal\Core\Field\FieldDefinitionListener $field_definition_listener*/
$field_definition_listener = \Drupal::service('field_definition.listener');
/** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_manager */
$bundle_manager = \Drupal::service('entity_type.bundle.info');
$bundle_info = $bundle_manager->getBundleInfo('commerce_order_item');
$order_item_types = OrderItemType::loadMultiple(array_keys($bundle_info));
$state = [];
foreach ($order_item_types as $order_item_type) {
if ($order_item_type->getOrderTypeId() == 'contacts_booking') {
// Check each bundle for commerce_order_item. If it's for the booking
// order type, add the state and confirmed fields if they don't have it
// already.
$field_definitions = $entity_field_manager->getFieldDefinitions('commerce_order_item', $order_item_type->id());
if (!isset($field_definitions['state'])) {
$state_field = BundleFieldDefinition::create('state')
->setName('state')
->setTargetEntityTypeId('commerce_order_item')
->setTargetBundle($order_item_type->id())
->setLabel(new TranslatableMarkup('State'))
->setDescription(new TranslatableMarkup('The order item state.'))
->setRequired(TRUE)
->setSetting('max_length', 255)
->setSetting('workflow', 'contacts_events_order_item_process')
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'state_transition_form',
'weight' => 10,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$field_definition_listener->onFieldDefinitionCreate($state_field);
$state[$order_item_type->id()][] = 'state';
}
if (!isset($field_definitions['confirmed'])) {
$confirmed_field = BundleFieldDefinition::create('timestamp')
->setName('confirmed')
->setTargetEntityTypeId('commerce_order_item')
->setTargetBundle($order_item_type->id())
->setLabel(new TranslatableMarkup('Confirmed'))
->setDescription(new TranslatableMarkup('The time when the order item was confirmed.'))
->setReadOnly(TRUE)
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', TRUE);
$field_definition_listener->onFieldDefinitionCreate($confirmed_field);
$state[$order_item_type->id()][] = 'confirmed';
}
}
}
if (!empty($state)) {
// Cache which fields were created so they can be populated using the
// populate-order-item-missing-fields.php script.
\Drupal::state()->set('contacts_events_install_order_item_fields', $state);
}
}
/**
* Migrate rules expression to new date range config.
*/
function contacts_events_update_8009() {
// Load all event classes.
$storage = \Drupal::entityTypeManager()->getStorage('contacts_events_class');
/** @var \Drupal\contacts_events\Entity\EventClass[] $classes */
$classes = $storage->loadMultiple();
$to_save = [];
foreach ($classes as $class) {
$expr = $class->get('expression');
$min_age = NULL;
$max_age = NULL;
if (!empty($expr)) {
if ($expr['id'] !== 'rules_and') {
throw new \Exception("Can't automatically migrate class {$class->label()}");
}
foreach ($expr['conditions'] as $condition) {
if (isset($condition['context_values']['operation']) && $condition['context_values']['operation'] == '<') {
if ($condition['context_mapping']['data'] != 'order_item.purchased_entity.entity.date_of_birth.date') {
throw new \Exception("Can't automatically migrate class {$class->label()} - not acting upon DOB.");
}
if (isset($min_age)) {
throw new \Exception("Can't automatically migrate class {$class->label()} - found multiple minimum ages");
}
if (empty($condition['context_processors']['value'])) {
// No minimum.
continue;
}
$interval = $condition['context_processors']['value']['rules_dynamic_date']['interval'] ?? NULL;
if ($interval == NULL) {
throw new \Exception("Can't automatically migrate class {$class->label()} - can't find date interval.");
}
if (substr($interval, 0, 1) !== 'P' || substr($interval, -1) !== 'Y') {
throw new \Exception("Can't automatically migrate class {$class->label()} - interval in wrong format");
}
$age = substr($interval, 1, strlen($interval) - 2);
if (!is_numeric($age)) {
throw new \Exception("Couldn't migrate class {$class->label()} - can't extract min age");
}
$min_age = (int) $age;
}
elseif (isset($condition['context_values']['operation']) && $condition['context_values']['operation'] == '>') {
if ($condition['context_mapping']['data'] != 'order_item.purchased_entity.entity.date_of_birth.date') {
throw new \Exception("Can't automatically migrate class {$class->label()} - not acting upon DOB.");
}
if (isset($max_age)) {
throw new \Exception("Can't automatically migrate class {$class->label()} - found multiple max ages");
}
if (empty($condition['context_processors']['value'])) {
// No maximum.
continue;
}
$interval = $condition['context_processors']['value']['rules_dynamic_date']['interval'] ?? NULL;
if ($interval == NULL) {
throw new \Exception("Can't automatically migrate class {$class->label()} - can't find date interval.");
}
if (substr($interval, 0, 1) !== 'P' || substr($interval, -1) !== 'Y') {
throw new \Exception("Can't automatically migrate class {$class->label()} - interval in wrong format");
}
$age = substr($interval, 1, strlen($interval) - 2);
if (!is_numeric($age)) {
throw new \Exception("Couldn't migrate class {$class->label()} - can't extract min age");
}
$age = (int) $age;
// Old format max age is exclusive, so decrement by 1.
$age--;
$max_age = $age;
}
}
}
if ($min_age !== NULL) {
$class->set('min_age', $min_age);
}
if ($max_age !== NULL) {
$class->set('max_age', $max_age);
}
$to_save[] = $class;
}
foreach ($to_save as $entity) {
$entity->save();
}
}
