-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstanford_migrate.module
executable file
·339 lines (306 loc) · 13.1 KB
/
stanford_migrate.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
<?php
/**
* @file
* Contains stanford_migrate.module.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\migrate_plus\Entity\Migration;
use Drupal\node\NodeInterface;
use Drupal\ultimate_cron\CronJobInterface;
use Drupal\migrate_plus\Entity\MigrationInterface as MigrationEntityInterface;
/**
* Implements hook_help().
*/
function stanford_migrate_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the stanford_migrate module.
case 'help.page.stanford_migrate':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Adds more functionality to migrate and migrate plus modules') . '</p>';
return $output;
default:
}
}
/**
* Implements hook_migrate_prepare_row().
*/
function stanford_migrate_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
// Oauth2 authentication adds a token query parameter into the data urls that changes frequently. Since it
// changes, the hash of the row changes without any data actually changing. Fix the row data so that it doesn't
// contain those tokens.
$authentication = $row->getSourceProperty('authentication/plugin');
$current_url = $row->getSourceProperty('current_feed_url');
if ($current_url && $authentication == 'oauth2') {
$row->setSourceProperty('current_feed_url', preg_replace('/access_token=.*?&/', '', $current_url));
}
// In case the list of urls changes dynamically, lets just remove it from the source data to avoid unnecessary hash
// changes.
$row->setSourceProperty('urls', []);
}
/**
* Get the migration that imported the given node.
*
* @param \Drupal\node\NodeInterface $node
* Node entity.
*
* @return array|\Drupal\migrate_plus\Entity\MigrationInterface|mixed
* Migration entity or null/false if none found.
*
* @deprecated in 8.2.3 and is removed in 9.0.0. Use
* \Drupal::service('stanford_migrate')->getNodesMigration() instead.
*/
function stanford_migrate_get_migration(NodeInterface $node) {
return \Drupal::service('stanford_migrate')->getNodesMigration($node);
}
/**
* Implements hook_entity_form_display_alter().
*/
function stanford_migrate_entity_form_display_alter(EntityFormDisplayInterface $form_display, array $context) {
// We only care about nodes, but this could be expanded later if more entities
// are imported.
$node = \Drupal::routeMatch()->getParameter('node');
if ($context['entity_type'] != 'node' || !$node) {
return;
}
$migration = \Drupal::service('stanford_migrate')->getNodesMigration($node);
// Check if the current node was imported.
if (!$migration) {
return;
}
// Grab the default display settings for use later.
$default_display = EntityViewDisplay::load("node.{$node->bundle()}.default");
$field_definitions = $form_display->get('fieldDefinitions');
foreach ($form_display->getComponents() as $field_name => $component) {
// Make sure the field component is one of the field definitions.
if (empty($field_definitions[$field_name])) {
continue;
}
// When edit an existing node that was imported via migrate module, mark the
// fields that are mapped from migration as readonly.
$field_definition = $field_definitions[$field_name];
$columns = $field_definition->getFieldStorageDefinition()->getColumns();
$processing = !empty($migration->process[$field_name]) || !empty($migration->process["$field_name/0"]);
// This will check if a migrate process is mapped to a specific column on
// the field.
foreach (array_keys($columns) as $column) {
$processing = $processing ?: !empty($migration->process["$field_name/$column"]) || !empty($migration->process["$field_name/0/$column"]);
}
// If the migration destination has the `overwrite_properties` configured,
// those fields specifically should be locked, not the other fields that
// are not designated in the original process configuration.
if ($processing && !empty($migration->get('destination')['overwrite_properties'])) {
// If the current field doesn't exist in the overwrite_properties, it
// should not be considered to be processing since it's a one time only
// import.
$processing = FALSE;
foreach ($migration->get('destination')['overwrite_properties'] as $overwrite_property) {
// If any part of the field is set to overwrite, lock the whole field
// down.
$overwrite_property = strstr($overwrite_property, '/', TRUE) ?: $overwrite_property;
if ($field_name == $overwrite_property) {
$processing = TRUE;
}
}
}
if ($processing) {
\Drupal::messenger()
->addWarning(t('Some fields can not be edited since they contain imported & synced data.'));
// If the default display is configured with some settings, let's use that
// for the best display on the entity form. If it's not configured, the
// readonly_field_widget module will use some default display settings.
if ($display_component = $default_display->getComponent($field_name)) {
$component['settings']['formatter_type'] = $display_component['type'];
$component['settings']['formatter_settings'][$display_component['type']] = $display_component['settings'];
$component['settings']['formatter_third_party_settings'] = $display_component['third_party_settings'] ?? [];
// Add the empty fields module settings to display a message.
$component['settings']['formatter_third_party_settings']['empty_fields']['handler'] = 'text';
$component['settings']['formatter_third_party_settings']['empty_fields']['settings']['empty_text'] = '<em>' . t('No Data') . '</em>';
$component['settings']['formatter_third_party_settings']['stanford_migrate']['readonly'] = TRUE;
}
$component['type'] = 'readonly_field_widget';
$form_display->setComponent($field_name, $component);
}
}
}
/**
* Implements hook_preprocess_HOOK().
*/
function stanford_migrate_preprocess_field(&$variables) {
if ($variables['element']['#third_party_settings']['stanford_migrate']['readonly'] ?? FALSE) {
// Wrap the readonly form fields with classes so that they can be identified
// more easily to the user.
$variables['attributes']['class'][] = 'messages';
$variables['attributes']['class'][] = 'messages--warning';
$variables['attributes']['class'][] = 'messages--readonly';
$variables['#attached']['library'][] = 'stanford_migrate/readonly';
}
}
/**
* Implements hook_config_readonly_whitelist_patterns().
*/
function stanford_migrate_config_readonly_whitelist_patterns() {
$configs = [];
/** @var \Drupal\migrate_plus\Entity\MigrationInterface $migration */
foreach (Migration::loadMultiple() as $migration) {
if ($migration->get('source')['plugin'] == 'csv') {
$configs[] = $migration->getConfigDependencyName();
}
}
return $configs;
}
/**
* Migration callback to just get the current timestamp.
*
* We use this function in migration callback processes because using `time` as
* the callback produces messages about "function accepts 0 arguments, 1
* argument passed". So we just have our own callback that takes the argument
* from the migration process and does nothing with it.
*
* @param mixed $arg
* Passed parameter from migration plugin `callback`.
*
* @return int
* Current timestamp.
*
* @see \Drupal\migrate\Plugin\migrate\process\Callback::transform()
*/
function _stanford_migrate_get_time($arg = NULL) {
return time();
}
/**
* Implements hook_entity_type_alter().
*/
function stanford_migrate_entity_type_alter(array &$entity_types) {
if (\Drupal::moduleHandler()->moduleExists('migrate_source_csv')) {
$entity_types['migration']->setFormClass('csv-upload', 'Drupal\stanford_migrate\Form\StanfordMigrateCsvImportForm');
$entity_types['migration']->setLinkTemplate('csv-upload', '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/csv-upload');
$entity_types['migration']->setLinkTemplate('csv-template', '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/csv-template');
}
}
/**
* Implements hook_ENTITY_TYPE_access().
*/
function stanford_migrate_migration_access(MigrationEntityInterface $entity, $operation, AccountInterface $account) {
if ($operation != 'csv') {
return AccessResult::neutral();
}
$migration_id = $entity->id();
return AccessResult::allowedIfHasPermission($account, "import $migration_id migration");
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function stanford_migrate_migration_delete(Migration $entity) {
// Clean up the state if the migration is deleted.
\Drupal::state()->delete("stanford_migrate.csv.{$entity->id()}");
}
/**
* Implements hook_migrate_id_map_info_alter().
*/
function stanford_migrate_migrate_id_map_info_alter(&$definitions) {
$definitions['sql']['class'] = '\Drupal\stanford_migrate\Plugin\migrate\id_map\StanfordSql';
}
/**
* Implements hook_migrate_source_info_alter().
*/
function stanford_migrate_migrate_source_info_alter(array &$definitions) {
$definitions['url']['class'] = '\Drupal\stanford_migrate\Plugin\migrate\source\StanfordUrl';
}
/**
* Implements hook_data_parser_info_alter().
*/
function stanford_migrate_data_parser_info_alter(array &$definitions) {
$definitions['json']['class'] = '\Drupal\stanford_migrate\Plugin\migrate_plus\data_parser\StanfordJson';
$definitions['simple_xml']['class'] = '\Drupal\stanford_migrate\Plugin\migrate_plus\data_parser\StanfordSimpleXml';
}
/**
* Implements hook_migrate_process_info_alter().
*/
function stanford_migrate_migrate_process_info_alter(array &$definitions) {
if (!empty($definitions['file_import'])) {
$definitions['file_import']['class'] = '\Drupal\stanford_migrate\Plugin\migrate\process\StanfordFileImport';
}
}
/**
* Implements hook_entity_delete().
*
* When an entity is manually deleted from the database, we want to remove it
* from the migration mapping.
*/
function stanford_migrate_entity_delete(EntityInterface $entity) {
\Drupal::service('stanford_migrate')->deleteEntityFromMigration($entity);
}
/**
* Ultimate cron callback function to execute a migration group.
*
* The entity id should be in the form `stanford_migrate_{migrate_group_id}` to
* execute that group.
*
* @param \Drupal\ultimate_cron\CronJobInterface $cron_entity
* Ultimate cron entity.
*/
function stanford_migrate_ultimate_cron_task(CronJobInterface $cron_entity) {
// Invalidate migration plugins to gather any changes to config entities
// before running import. This allows for any changes to the source urls.
\Drupal::service('plugin.manager.migration')->clearCachedDefinitions();
Cache::invalidateTags(['migration_plugins']);
/** @var \Drupal\stanford_migrate\StanfordMigrateInterface $migrate_service */
$migrate_service = \Drupal::service('stanford_migrate');
$migrations = $migrate_service->getMigrationList();
$migration_group = str_replace('stanford_migrate_', '', $cron_entity->id());
// Execute the migration entities in the provided migration group.
if ($migration_group && !empty($migrations[$migration_group])) {
return array_walk($migrations[$migration_group], [
$migrate_service,
'executeMigration',
]);
}
\Drupal::logger('stanford_migrate')
->info('No migration group @group exists. No migration executed.', ['@group' => $migration_group]);
}
/**
* Executes a single migration, taken from drush command in migrate_tools.
*
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration to execute.
* @param string $migration_id
* The migration ID (not used, just an artifact of array_walk()).
* @param array $options
* Array of options to pass into the migration import.
* @param bool $batch
* Execute the migration using a batch process.
*
* @deprecated in 8.2.3 and is removed in 9.0.0. Use
* \Drupal::service('stanford_migrate')->executeMigration() instead.
*
* @see \Drupal\migrate_tools\Drush\MigrateToolsCommands::executeMigration()
*/
function stanford_migrate_execute_migration(MigrationInterface $migration, string $migration_id, array $options = [], bool $batch = FALSE): void {
\Drupal::service('stanford_migrate')
->executeMigration($migration, $migration_id, $options, $batch);
}
/**
* Retrieve a list of active migrations, partially taken from migrate_tools.
*
* @return \Drupal\migrate\Plugin\MigrationInterface[][]
* An array keyed by migration group, each value containing an array of
* migrations or an empty array if no migrations match the input criteria.
*
* @deprecated in 8.2.3 and is removed in 9.0.0. Use
* \Drupal::service('stanford_migrate')->getMigrationList() instead.
*
* @see \Drupal\migrate_tools\Drush\MigrateToolsCommands::migrationsList()
*/
function stanford_migrate_migration_list() {
return \Drupal::service('stanford_migrate')->getMigrationList();
}