From 38f62621b1393bd4ee1e66d9ca576c9b1054ac57 Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Tue, 21 Nov 2017 12:03:46 +0100 Subject: [PATCH] upgraded contrib modules --- .../contrib/admin/admin_toolbar/CHANGELOG.txt | 293 ++++++ .../contrib/admin/admin_toolbar/README.txt | 84 +- .../admin_toolbar/admin_toolbar.info.yml | 10 +- .../admin/admin_toolbar/admin_toolbar.module | 11 +- .../README.txt | 61 ++ ...admin_toolbar_links_access_filter.info.yml | 12 + .../admin_toolbar_links_access_filter.module | 176 ++++ .../admin_toolbar_tools/README.txt | 80 +- .../admin_toolbar_tools.info.yml | 10 +- .../admin_toolbar_tools.links.menu.yml | 50 +- .../admin_toolbar_tools.module | 119 ++- .../admin_toolbar_tools.routing.yml | 47 +- .../admin_toolbar_tools.services.yml | 4 + .../src/Controller/ToolbarController.php | 144 +-- .../src/Tests/AdminToolbarToolsAlterTest.php | 2 +- .../src/ToolbarHandler.php | 135 +++ .../admin/admin_toolbar/css/admin.toolbar.css | 23 +- .../admin/admin_toolbar/js/admin_toolbar.js | 34 +- .../src/Tests/AdminToolbarAlterTest.php | 4 +- .../dev/config_devel/config_devel.info.yml | 6 +- .../dev/config_devel/drush.services.yml | 13 + .../config_devel/drush/config_devel.drush.inc | 12 + .../src/Commands/ConfigDevelCommands.php | 353 +++++++ .../contrib/migrate/migrate_plus/LICENSE.txt | 339 +++++++ .../contrib/migrate/migrate_plus/README.txt | 77 ++ .../migrate/migrate_plus/composer.json | 24 + .../schema/migrate_plus.data_types.schema.yml | 40 + .../migrate_plus.destination.schema.yml | 18 + .../schema/migrate_plus.process.schema.yml | 145 +++ .../config/schema/migrate_plus.schema.yml | 78 ++ .../schema/migrate_plus.source.schema.yml | 34 + .../migrate_plus/migrate_example/README.txt | 111 +++ .../migrate_plus.migration.beer_node.yml | 53 ++ .../migrate_plus.migration.beer_term.yml | 87 ++ .../migrate_plus.migration.beer_user.yml | 105 ++ .../migrate_plus.migration_group.beer.yml | 38 + .../migrate_example/migrate_example.info.yml | 15 + .../install/comment.type.node_comments.yml | 7 + ..._display.comment.node_comments.default.yml | 30 + ...play.node.migrate_example_beer.default.yml | 87 ++ ..._display.comment.node_comments.default.yml | 22 + ...play.node.migrate_example_beer.default.yml | 60 ++ ...splay.node.migrate_example_beer.teaser.yml | 35 + ...eld.comment.node_comments.comment_body.yml | 20 + ...d.field.node.migrate_example_beer.body.yml | 21 + ...de.migrate_example_beer.field_comments.yml | 32 + ..._beer.field_migrate_example_beer_style.yml | 26 + ...ple_beer.field_migrate_example_country.yml | 18 + ...ample_beer.field_migrate_example_image.yml | 37 + ...er.user.field_migrate_example_favbeers.yml | 27 + ...user.user.field_migrate_example_gender.yml | 19 + .../field.storage.node.field_comments.yml | 19 + ....node.field_migrate_example_beer_style.yml | 19 + ...age.node.field_migrate_example_country.yml | 20 + ...orage.node.field_migrate_example_image.yml | 29 + ...ge.user.field_migrate_example_favbeers.yml | 19 + ...rage.user.field_migrate_example_gender.yml | 20 + .../node.type.migrate_example_beer.yml | 9 + ...vocabulary.migrate_example_beer_styles.yml | 8 + .../migrate_example_setup.info.yml | 18 + .../migrate_example_setup.install | 345 +++++++ .../migrations/beer_comment.yml | 45 + .../src/Plugin/migrate/source/BeerComment.php | 56 ++ .../src/Plugin/migrate/source/BeerNode.php | 99 ++ .../src/Plugin/migrate/source/BeerTerm.php | 88 ++ .../src/Plugin/migrate/source/BeerUser.php | 85 ++ .../migrate_example_advanced/README.txt | 58 ++ .../migrate_plus.migration.weather_soap.yml | 50 + .../migrate_plus.migration.wine_role_json.yml | 55 ++ .../migrate_plus.migration.wine_role_xml.yml | 51 + .../migrate_plus.migration.wine_terms.yml | 37 + ...e_plus.migration.wine_variety_list.yml.txt | 56 ++ ..._plus.migration.wine_variety_multi_xml.yml | 69 ++ .../migrate_plus.migration_group.wine.yml | 11 + .../migrate_example_advanced/data/0001.xml | 7 + .../migrate_example_advanced/data/0002.xml | 7 + .../migrate_example_advanced/data/index.xml | 4 + .../migrate_example_advanced/data/index2.xml | 4 + .../migrate_example_advanced.info.yml | 15 + .../migrate_example_advanced.install | 50 + ....type.migrate_example_advanced_comment.yml | 7 + ...grate_example_advanced_comment.default.yml | 30 + ....node.migrate_example_producer.default.yml | 69 ++ ...play.node.migrate_example_wine.default.yml | 117 +++ ...migrate_example_wine_varieties.default.yml | 41 + ...grate_example_advanced_comment.default.yml | 22 + ....node.migrate_example_producer.default.yml | 33 + ...y.node.migrate_example_producer.teaser.yml | 27 + ...play.node.migrate_example_wine.default.yml | 88 ++ ...splay.node.migrate_example_wine.teaser.yml | 39 + ...migrate_example_wine_varieties.default.yml | 27 + ..._example_advanced_comment.comment_body.yml | 20 + ...eld.node.migrate_example_producer.body.yml | 21 + ...ducer.field_migrate_example_wine_regio.yml | 26 + ...d.field.node.migrate_example_wine.body.yml | 21 + ...e_wine.field_migrate_example_adv_image.yml | 37 + ...le_wine.field_migrate_example_comments.yml | 32 + ..._wine.field_migrate_example_top_vintag.yml | 22 + ...e_wine.field_migrate_example_wine_best.yml | 26 + ..._wine.field_migrate_example_wine_ratin.yml | 22 + ..._wine.field_migrate_example_wine_regio.yml | 26 + ...le_wine.field_migrate_example_wine_var.yml | 26 + ...ine_varieties.field_variety_attributes.yml | 18 + ...e.node.field_migrate_example_adv_image.yml | 29 + ...ge.node.field_migrate_example_comments.yml | 19 + ....node.field_migrate_example_top_vintag.yml | 19 + ...e.node.field_migrate_example_wine_best.yml | 19 + ....node.field_migrate_example_wine_ratin.yml | 19 + ....node.field_migrate_example_wine_regio.yml | 19 + ...ge.node.field_migrate_example_wine_var.yml | 19 + ...taxonomy_term.field_variety_attributes.yml | 20 + .../node.type.migrate_example_producer.yml | 10 + .../node.type.migrate_example_wine.yml | 10 + ...urce.migrate_example_advanced_position.yml | 10 + ...migrate_example_advanced_variety_items.yml | 10 + ....migrate_example_advanced_variety_list.yml | 10 + ...rate_example_advanced_variety_multiple.yml | 10 + ...abulary.migrate_example_wine_best_with.yml | 8 + ...ocabulary.migrate_example_wine_regions.yml | 8 + ...abulary.migrate_example_wine_varieties.yml | 8 + .../migrate_example_advanced_setup.info.yml | 18 + .../migrate_example_advanced_setup.install | 895 ++++++++++++++++++ .../Plugin/rest/resource/PositionResource.php | 44 + .../src/Plugin/rest/resource/VarietyItems.php | 72 ++ .../src/Plugin/rest/resource/VarietyList.php | 42 + .../rest/resource/VarietyMultiFiles.php | 83 ++ .../src/Plugin/migrate/source/WineTerm.php | 50 + .../migrate_plus/migrate_plus.info.yml | 13 + .../migrate/migrate_plus/migrate_plus.install | 38 + .../migrate/migrate_plus/migrate_plus.module | 87 ++ .../migrate_plus/migrate_plus.services.yml | 10 + .../migrations/migration_config_deriver.yml | 6 + .../src/Annotation/Authentication.php | 37 + .../src/Annotation/DataFetcher.php | 37 + .../src/Annotation/DataParser.php | 37 + .../src/AuthenticationPluginBase.php | 25 + .../src/AuthenticationPluginInterface.php | 25 + .../src/AuthenticationPluginManager.php | 37 + .../src/DataFetcherPluginBase.php | 32 + .../src/DataFetcherPluginInterface.php | 49 + .../src/DataFetcherPluginManager.php | 37 + .../migrate_plus/src/DataParserPluginBase.php | 220 +++++ .../src/DataParserPluginInterface.php | 15 + .../src/DataParserPluginManager.php | 37 + .../migrate_plus/src/Entity/Migration.php | 83 ++ .../src/Entity/MigrationGroup.php | 77 ++ .../src/Entity/MigrationGroupInterface.php | 12 + .../src/Entity/MigrationInterface.php | 12 + .../migrate_plus/src/Event/MigrateEvents.php | 29 + .../src/Event/MigratePrepareRowEvent.php | 84 ++ .../src/Plugin/MigrationConfigDeriver.php | 28 + .../src/Plugin/migrate/destination/Table.php | 128 +++ .../Plugin/migrate/process/EntityGenerate.php | 101 ++ .../Plugin/migrate/process/EntityLookup.php | 249 +++++ .../src/Plugin/migrate/process/FileBlob.php | 155 +++ .../src/Plugin/migrate/process/Merge.php | 68 ++ .../Plugin/migrate/process/SkipOnValue.php | 87 ++ .../migrate/source/SourcePluginExtension.php | 60 ++ .../src/Plugin/migrate/source/Url.php | 139 +++ .../migrate_plus/authentication/Basic.php | 30 + .../migrate_plus/authentication/Digest.php | 31 + .../migrate_plus/authentication/OAuth2.php | 69 ++ .../Plugin/migrate_plus/data_fetcher/File.php | 52 + .../Plugin/migrate_plus/data_fetcher/Http.php | 104 ++ .../Plugin/migrate_plus/data_parser/Json.php | 133 +++ .../migrate_plus/data_parser/SimpleXml.php | 87 ++ .../Plugin/migrate_plus/data_parser/Soap.php | 123 +++ .../Plugin/migrate_plus/data_parser/Xml.php | 321 +++++++ .../migrate_plus/data_parser/XmlTrait.php | 65 ++ .../tests/src/Kernel/MigrateTableTest.php | 136 +++ .../src/Kernel/MigrationConfigEntityTest.php | 52 + .../tests/src/Kernel/MigrationGroupTest.php | 121 +++ .../migrate/process/EntityGenerateTest.php | 328 +++++++ .../src/Unit/process/SkipOnValueTest.php | 112 +++ .../contrib/migrate/migrate_tools/LICENSE.txt | 339 +++++++ .../contrib/migrate/migrate_tools/README.txt | 15 + .../migrate/migrate_tools/composer.json | 11 + .../migrate/migrate_tools/drush.services.yml | 6 + .../migrate_tools/migrate_tools.drush.inc | 524 ++++++++++ .../migrate_tools/migrate_tools.info.yml | 14 + .../migrate_tools.links.action.yml | 11 + .../migrate_tools.links.menu.yml | 5 + .../migrate_tools.links.task.yml | 41 + .../migrate_tools/migrate_tools.module | 29 + .../migrate_tools.permissions.yml | 3 + .../migrate_tools/migrate_tools.routing.yml | 124 +++ .../contrib/migrate/migrate_tools/phpcs.xml | 126 +++ .../src/Commands/MigrateToolsCommands.php | 741 +++++++++++++++ .../src/Controller/MessageController.php | 144 +++ .../src/Controller/MigrationController.php | 311 ++++++ .../Controller/MigrationGroupListBuilder.php | 68 ++ .../src/Controller/MigrationListBuilder.php | 228 +++++ .../src/Drush9LogMigrateMessage.php | 48 + .../src/DrushLogMigrateMessage.php | 23 + .../src/Form/MigrationAddForm.php | 37 + .../src/Form/MigrationDeleteForm.php | 71 ++ .../src/Form/MigrationEditForm.php | 51 + .../src/Form/MigrationExecuteForm.php | 231 +++++ .../src/Form/MigrationFormBase.php | 194 ++++ .../src/Form/MigrationGroupAddForm.php | 37 + .../src/Form/MigrationGroupDeleteForm.php | 71 ++ .../src/Form/MigrationGroupEditForm.php | 37 + .../src/Form/MigrationGroupFormBase.php | 182 ++++ .../src/MigrateBatchExecutable.php | 290 ++++++ .../migrate_tools/src/MigrateExecutable.php | 366 +++++++ .../migrate_plus.migration.fruit_terms.yml | 32 + .../migrate_plus.migration_group.default.yml | 9 + .../migrate_tools_test.info.yml | 14 + .../Functional/MigrateExecutionFormTest.php | 132 +++ .../migrate/migrate_upgrade/LICENSE.txt | 339 +++++++ .../migrate/migrate_upgrade/README.txt | 87 ++ .../migrate/migrate_upgrade/composer.json | 11 + .../migrate_upgrade/migrate_upgrade.drush.inc | 93 ++ .../migrate_upgrade/migrate_upgrade.info.yml | 16 + .../contrib/migrate/migrate_upgrade/phpcs.xml | 126 +++ .../src/DrushLogMigrateMessage.php | 23 + .../src/MigrateUpgradeDrushRunner.php | 324 +++++++ 217 files changed, 16074 insertions(+), 217 deletions(-) create mode 100644 sites/all/modules/contrib/admin/admin_toolbar/CHANGELOG.txt create mode 100644 sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/README.txt create mode 100644 sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.info.yml create mode 100644 sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module create mode 100644 sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.services.yml create mode 100644 sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/ToolbarHandler.php create mode 100644 sites/all/modules/contrib/dev/config_devel/drush.services.yml create mode 100644 sites/all/modules/contrib/dev/config_devel/src/Commands/ConfigDevelCommands.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/LICENSE.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/README.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/composer.json create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.data_types.schema.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.destination.schema.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.process.schema.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.schema.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.source.schema.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/README.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_node.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_term.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_user.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration_group.beer.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/comment.type.node_comments.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.comment.node_comments.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.node.migrate_example_beer.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.comment.node_comments.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.teaser.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.comment.node_comments.comment_body.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.body.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_comments.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_beer_style.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_country.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_image.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_favbeers.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_gender.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_comments.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_beer_style.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_country.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_image.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_favbeers.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_gender.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/node.type.migrate_example_beer.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/taxonomy.vocabulary.migrate_example_beer_styles.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.install create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrations/beer_comment.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerComment.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerNode.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerTerm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerUser.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/README.txt create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_json.yml create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_xml.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_terms.yml create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_list.yml.txt create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_multi_xml.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration_group.wine.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0001.xml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0002.xml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index.xml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index2.xml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.install create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/comment.type.migrate_example_advanced_comment.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.comment.migrate_example_advanced_comment.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_producer.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_wine.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.taxonomy_term.migrate_example_wine_varieties.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.comment.migrate_example_advanced_comment.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.teaser.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.teaser.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.taxonomy_term.migrate_example_wine_varieties.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.comment.migrate_example_advanced_comment.comment_body.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.body.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.field_migrate_example_wine_regio.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.body.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_adv_image.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_comments.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_top_vintag.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_best.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_ratin.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_regio.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_var.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.taxonomy_term.migrate_example_wine_varieties.field_variety_attributes.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_adv_image.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_comments.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_top_vintag.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_best.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_ratin.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_regio.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_var.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.taxonomy_term.field_variety_attributes.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_producer.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_wine.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_position.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_items.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_list.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_multiple.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_best_with.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_regions.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_varieties.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.install create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/PositionResource.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyItems.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyList.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyMultiFiles.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/src/Plugin/migrate/source/WineTerm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.install create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.module create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.services.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/migrations/migration_config_deriver.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Annotation/Authentication.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Annotation/DataFetcher.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Annotation/DataParser.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/AuthenticationPluginBase.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/AuthenticationPluginInterface.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/AuthenticationPluginManager.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/DataFetcherPluginBase.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/DataFetcherPluginInterface.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/DataFetcherPluginManager.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginBase.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginInterface.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginManager.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Entity/Migration.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroup.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroupInterface.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationInterface.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Event/MigrateEvents.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Event/MigratePrepareRowEvent.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/MigrationConfigDeriver.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/destination/Table.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityGenerate.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityLookup.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/FileBlob.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/Merge.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/SkipOnValue.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/SourcePluginExtension.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/Url.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Basic.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Digest.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/OAuth2.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/File.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/Http.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Json.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/SimpleXml.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Soap.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Xml.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/XmlTrait.php create mode 100755 sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrateTableTest.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationConfigEntityTest.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationGroupTest.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/Plugin/migrate/process/EntityGenerateTest.php create mode 100644 sites/all/modules/contrib/migrate/migrate_plus/tests/src/Unit/process/SkipOnValueTest.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/LICENSE.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/README.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/composer.json create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/drush.services.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.drush.inc create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.action.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.menu.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.task.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.module create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.permissions.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.routing.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/phpcs.xml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Commands/MigrateToolsCommands.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MessageController.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationController.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationGroupListBuilder.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationListBuilder.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Drush9LogMigrateMessage.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/DrushLogMigrateMessage.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationAddForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationDeleteForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationEditForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationExecuteForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationFormBase.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupAddForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupDeleteForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupEditForm.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupFormBase.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/MigrateBatchExecutable.php create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/src/MigrateExecutable.php create mode 100755 sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration.fruit_terms.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration_group.default.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/migrate_tools_test.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_tools/tests/src/Functional/MigrateExecutionFormTest.php create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/LICENSE.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/README.txt create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/composer.json create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.drush.inc create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.info.yml create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/phpcs.xml create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/src/DrushLogMigrateMessage.php create mode 100644 sites/all/modules/contrib/migrate/migrate_upgrade/src/MigrateUpgradeDrushRunner.php diff --git a/sites/all/modules/contrib/admin/admin_toolbar/CHANGELOG.txt b/sites/all/modules/contrib/admin/admin_toolbar/CHANGELOG.txt new file mode 100644 index 000000000..e4a5c8163 --- /dev/null +++ b/sites/all/modules/contrib/admin/admin_toolbar/CHANGELOG.txt @@ -0,0 +1,293 @@ +Admin Toolbar 8.1.21, 2017-11-20 +-------------------------------- +Changes since 8.1.20: + +- #2923580 by sylus, adriancid: Unsupported operand types in + ToolbarHandler::lazyBuilder(). +- #2731369 by stefan.r, DuneBL, Berdir, kbasarab, joachim, adriancid: Local + tasks don't show in the toolbar. +- #2920793 by adriancid: Change the user TAKTAK by matio89 in the CHANGELOG.txt + file. +- #2873228 by smustgrave, adriancid, flocondetoile: Toolbar menu accessible and + navigable with keyboard. +- #2919775 by adriancid: Create the CHANGELOG.txt file. +- #2919772 by adriancid: Use the README.txt template. +- #2919769 by adriancid: Use the README.txt template for the admin_toolbar_tools + submodule. +- #2897309 by finne, adriancid, eme, rgpublic: admin_toolbar_tools module + makes all pages uncacheable. +- #2913299 by esod, Chi, adriancid, hudri, eme: CSS Z-Index of toolbar is + inappropriate. +- #2919390 by adriancid: Create the README.txt file for the admin toolbar links + access filter submodule. +- #2919367 by adriancid: Fix coding standard format. +- #2919346 by adriancid: Don't show menu links that you don't have access + permission for. +- #2917710: Create the .info.yml file for the admin_toolbar_links_access_filter + submodule. +- #2916064 by adriancid, eme, finne: Use in drupal.org links url parameter and + not route_name. +- #2916040 by adriancid, finne, eme: Remove unused route admin_development. +- #2915778 by finne, adriancid: Remove the _csrf_token from routes that don't + need it. +- #2909359 by adriancid, Musa.thomas: Add a menu link to clean the Views cache. +- #2910931 by adriancid: .info.yml files don't have the drupal version. +- #2759135 by Johnny vd Laar, miiimooo, romainj, chegor, adriancid, ckaotik, + bdominguez, SpadXIII, mrtndlmt: Content type, Vocabularies and Menus names are + not translated. +- #2909710 by adriancid, Musa.thomas: Fix coding standard format. +- #2910934 by adriancid, romainj: Error trying to clean the cache. +- #2910892 by adriancid: Delete the LICENSE.txt. +- #2909637 by bapi_22, Musa.thomas, adriancid: Avoid static call inside class + method. +- #2909003 by eme: fix z-index for CKEditor. +- #2504449 by robin.ingelbrecht, rwam, eme: Un-hover delay. + +Admin Toolbar 8.1.20, 2017-09-07 +-------------------------------- +Changes since 8.1.19: + +- #2887439 by romainj: Fix test. +- #2759135 by Johnny vd Laar, miiimooo, chegor, romainj: Content type, + Vocabularies and Menus names are not translated. +- #2894520 by romainj, bapi_22: Remove deprecated constant REQUEST_TIME from + code base. +- #2883098 by romainj, Alka Kumari: Admin Toolbar Extra Tools module display + theme machine names instead of labels. +- #2504449 by robin.ingelbrecht: Un-hover delay. +- #2838636 by ddrozdik, Fons Vandamme, kerby70, romainj: Issue with z-index of + dropdown in horizontal tray. +- #2838636 by Fons Vandamme, ddrozdik, romainj: Issue with z-index of dropdown + in horizontal tray. +- #2870404 by romainj: Add a link to the Webprofiler settings page. +- #2706643 by esod, romainj, Keenegan, DamienMcKenna: Use short array syntax. + +Admin Toolbar 8.1.19, 2017-04-06 +-------------------------------- +Changes since 8.1.18: + +- #2706643 by esod, romainj, Keenegan, DamienMcKenna: Use short array syntax. +- #2781745 by minakshiPh, eelkeblok, romainj, akhilavnair_zyxware: Drupal coding + standard issues found in most of the files. +- #2855720 by stefan.r, romainj: No logout link in admin toolbar anymore. +- #2841512 by Chi, romainj: User error: Redirects to external URLs are not + allowed by default. + +Admin Toolbar 8.1.18, 2016-12-01 +-------------------------------- +Changes since 8.1.17: + +- #2830677 by vaplas, romainj: z-index for sub menu. +- by romainj: Get rid of the Hello popup. +- #2805431 by marcusx: Accidentaly committed alert. +- #2630724 by squarecandy, romainj, reblutus, Hemangi Gokhale, jacoferg, + Balu Ertl, Jeff Burnz, Don Greco: Consider changes to link title parameter to + avoid tooltip visual conflict. +- #2518202 by james.williams, chegor, eme, romainj, DuneBL: Change default link + to taxonomy. + +Admin Toolbar 8.1.17, 2016-08-19 +-------------------------------- +Changes since 8.1.16: + +- #2779251 by romainj, DuneBL: Wrong integration of field_collection delete + form. +- #2776229 by Chi, romainj, mattlt: Chevron icons missing if Drupal is not in + document root. +- by romainj: CSS coding standard cleaning. +- #2781059 by mstrelan, romainj: Why is CRON in all caps? +- #2778935 by akhilavnair_zyxware, rjarraud: As per Drupal Standards each line + in documentation should not exceeds 80 characters. +- by romainj: Adds ending new line where required. +- #2776229 by Chi, rjarraud: Chevron icons missing if Drupal is not in document + root. +- by eme: Commiting again #2707611. +- #2757687 by neerajsingh: Remove usages of \Drupal::url(). +- #2707747 by Balu Ertl, nevergone, eme, esod: D8 logo not rendered with smooth + antialiasing. + +Admin Toolbar 8.1.16, 2016-07-28 +-------------------------------- +Changes since 8.1.15: + +- #2723209 by andrewmacpherson, colan, mattshoaf: Enabling admin_toolbar_tools + causes Devel Settings to disappear from the main configuration page. +- #2759335 bycwells, jalpesh: fixes a mistaken link in hook_help(). +- #2664564 by kolier, matio89, romainj and Michèle: auto-detect content entities + with Field UI route. +- #2735257 by colan, romainj, Balu Ertl: respect of coding standards in the + module README.txt file. +- #2735257 by colan, romainj, Balu Ertl: shortens the module README.txt + description text. +- by romainj: Fixes a problem with the link to the Admin menu overview page. +- #2735257 by Balu Ertl, colan, romainj: improves Admin Toolbar Extra Tools + description in the README.txt file. +- #2723381 by joachim, romainj: fieldable content entities are no more + hardcoded. +- #2735257 by Balu Ertl, colan, romainj: added some description details in the + README.txt files. +- by romainj: Menu link definitions updated. +- by romainj: Change routing permissions to follow Drupal default permissions + for administration pages. +- by romainj: Fixes issue #2737027. +- by romainj: fixes issue #2701825. +- by romainj: Adds the menu name for each menu item in + admin_toolbar_tools/admin_toolbar_tools.links.menu.yml file. +- #2735153 by Kionn: InvalidArgumentException: Cannot redirect to an empty URL. + в Symfony\Component\HttpFoundation\RedirectResponse->setTargetUrl(). +- by matio89: correction InvalidArgumentException: Cannot redirect to an empty + URL. в Symfony\Component\HttpFoundation\RedirectResponse->setTargetUrl(). +- by romainj: Add a new Render Cache shortcut on the admin menu. +- by romainj: Fixes issue #2731663 by canceling the move of the Logout menu + link. + +Admin Toolbar 8.1.15, 2016-05-23 +-------------------------------- +Changes since 8.1.14: + +- by matio89: add RTL in admin.toolbar.css. +- by romainj: Changes Devel menu item titles. +- by romainj: Fixes issue #2713899. +- by romainj: Minor code/typo cleaning. +- #2707611 by Balu Ertl: Add fine shadow under dropdown menus. +- #2707789 by esod: Fix Automated Tests. +- by romainj: Code cleaning. +- by romainj: Replace the deprecated entityManager() by entityTypeManager() + service. +- by romainj: Emptying menu cache with all link types. +- #2614962 by dbt102, seppelM, neha.gangwar, chegor: Correct text in + info.yml(s). +- by eme: Minor typo changes. +- by eme: Fix dependencies to core modules. +- by eme: Fix issue #2666964. +- by eme: Fix css background color level3. +- by eme: fix issue #2658896 and refactor and fix chevron-right.svg. +- by eme: fix Issue #2493037. + +Admin Toolbar 8.1.14, 2016-02-08 +-------------------------------- +Changes since 8.1.13: + +- by matio89: Correction differents bugs(problem white page when installing a + new module). +- #2643648 by Lord_of_Codes: Proposed README.txt file for Admin Toolbar. +- by matio89: resolving the dependecies problem(dependencies of others modules). +- by matio89: Correction route of entities. + +Admin Toolbar 8.1.13, 2016-02-02 +-------------------------------- +Changes since 8.1.12: + +- by matio89: Admin toolbar is compatible with 8.0.2. +- by matio89: Commmit dev version compatible with drupal 8.0.2. +- by matio89: New version of admin toolbar compatible with 8.0.2. + +Admin Toolbar 8.1.12, 2016-01-15 +-------------------------------- +Changes since 8.1.11: + +- by matio89: Correction AdminToolbaToolsAlterTest. +- #2493037 by mimran: Empty elements in #toolbar-bar. +- #2598136 by mimran, felribeiro: Menu items duplicated. +- #2635154 by Lukas von Blarer: Too general CSS selectors. +- by eme: Fix chevron right in local state. + +Admin Toolbar 8.1.11, 2015-12-11 +-------------------------------- +Changes since 8.1.10: + +- #2620430 by Vagelis, NarendraR: Typo. +- #2632888 by JamesK: Add dependency on node module. +- by eme: Fix admin toolbar test. +- #2552081 by jonhattan, bruvers: chevron-right.svg not found. +- by Vagelis: Minor typos. +- by eme: Refactor basic tests. +- #2613378 by chegor: Add basic test. +- #2612694 by chegor: Add new view. +- #2627918 by joe_carvajal: Version in info.yml files does Update Manager try to + update. +- by matio89: correction collapsible behaviour in vertical menu layout. +- #2582825 by Ben Coleman: Installing Admin Toolbar Tools loses anonymous user + login link. +- by matio89: Correction the login link on the site when in a logged-out state. + +Admin Toolbar 8.1.10, 2015-08-07 +-------------------------------- +Changes since 8.1.9: + +- #2546939 by jonhattan: Add dependency on toolbar module. + +Admin Toolbar 8.1.9, 2015-07-22 +------------------------------- +Changes since 8.1.8: + +- #2537016 by matio89: Removing dependance for user & system. +- #2533420 by Dave Reid, twistor: Chase HEAD changes in toolbar. +- #2537016 by twistor: Rewrite admin_toolbar_tools.module +- by matio89: Correction all bugs and add new security features. + +Admin Toolbar 8.1.8, 2015-06-22 +------------------------------- +Changes since 8.1.7: + +- correction not found route. +- #2493037 by bobrov1989: Empty elements in #toolbar-bar. +- by fethi: icones. + +Admin Toolbar 8.1.7, 2015-06-22 +------------------------------- +Changes since 8.1.6: + +- correction not found route. +- #2493037 by bobrov1989: Empty elements in #toolbar-bar. +- by fethi: icones. + +Admin Toolbar 8.1.6, 2015-06-03 +------------------------------- +Changes since 8.1.5: + +- by matio89: correction admin_toolbar. + +Admin Toolbar 8.1.5, 2015-06-03 +------------------------------- +Changes since 8.1.4: + +- by matio89: test if module update exist or no to display install and update + module. +- by fethi: Change the colors used to match the Seven styleguide. +- by matio89: compatibility with Drupal 8 béta 11. +- by fethi: Change the colors used to match the Seven styleguide. + +Admin Toolbar 8.1.4, 2015-05-20 +------------------------------- +Changes since 8.1.3: + +- by matio89: correction add/node. + +Admin Toolbar 8.1.3, 2015-05-19 +------------------------------- +Changes since 8.1.2: + +- by matio89: add new functionalities. +- by matio89: add administration devel link. +- by matio89: correction reload page. +- by matio89: correction redirect to the same page. + +Admin Toolbar 8.1.2, 2015-05-19 +------------------------------- +Changes since 8.1.1: + +- by matio89: add new functionalities. +- by matio89: add administration devel link. +- by matio89: correction reload page. +- by matio89: correction redirect to the same page. + +Admin Toolbar 8.1.1, 2015-05-19 +------------------------------- +Changes since 8.1.0: + +- by matio89: add new functionalities. + +Admin Toolbar 8.1.0, 2015-05-07 +------------------------------- +- Initial release. diff --git a/sites/all/modules/contrib/admin/admin_toolbar/README.txt b/sites/all/modules/contrib/admin/admin_toolbar/README.txt index 2c9c7b788..459cc2ca9 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/README.txt +++ b/sites/all/modules/contrib/admin/admin_toolbar/README.txt @@ -1,45 +1,69 @@ ----SUMMARY--- +CONTENTS OF THIS FILE +--------------------- -Admin Toolbar intends to improve the default Drupal Toolbar to transformit into + * Introduction + * Requirements + * Recommended modules + * Installation + * Configuration + * Maintainers + + +INTRODUCTION +------------ + +Admin Toolbar intends to improve the default Drupal Toolbar to transform it into a drop-down menu, providing a fast and full access to all administration links. -For a full description visit project page: -https://www.drupal.org/project/admin_toolbar + * For a full description of the module, visit the project page: + https://www.drupal.org/project/admin_toolbar -Bug reports, feature suggestions and latest developments: -http://drupal.org/project/issues/admin_toolbar + * To submit bug reports and feature suggestions, or to track changes: + https://www.drupal.org/project/issues/search/admin_toolbar ----REQUIREMENTS--- +REQUIREMENTS +------------ + +No special requirements. -*None. (Other than a clean Drupal 8 installation) +RECOMMENDED MODULES +------------------- + + * Admin Toolbar Extra Tools (https://www.drupal.org/project/admin_toolbar): + Provides menu links to administration pages or actions (eg. Flushing caches) + that are not generated by Drupal core. + + * Admin Toolbar Links Access Filter (https://www.drupal.org/node/2474539): + Provides a workaround for the common problem that users with + 'Use the administration pages and help' permission see menu links they don't + have access permission for. + +INSTALLATION +------------ + + * Install as you would normally install a contributed Drupal module. + See: https://www.drupal.org/node/895232 for further information. ----INSTALLATION--- +CONFIGURATION +------------- + +No configuration is needed. -Install as usual. - -Place the entirety of this directory in the /modules folder of your Drupal -installation. Navigate to Administer > Extend. Check the 'Enabled' box next -to the 'Admin toolbar' and/or 'Admin toolbar Extra Tools' and then click -the 'Save Configuration' button at the bottom. - -For help regarding installation, visit: -https://www.drupal.org/documentation/install/modules-themes/modules-8 - - ----CONTACT--- - - -Current Maintainers: -*Wilfrid Roze (eme) - https://www.drupal.org/u/eme -*Mohamed Anis Taktak (matio89) - https://www.drupal.org/u/matio89 +MAINTAINERS +----------- +Current maintainers: + * Wilfrid Roze (eme) - https://www.drupal.org/u/eme + * Romain Jarraud (romainj) - https://www.drupal.org/u/romainj + * Adrian Cid Almaguer (adriancid) - https://www.drupal.org/u/adriancid + * Mohamed Anis Taktak (matio89) - https://www.drupal.org/u/matio89 This project has been sponsored by: -*emerya -Founded in 2009, emerya is a human-sized company, dedicated to the design -and implementation of web interfaces. -Visit: http://http://emerya.fr/ for more information. + * emerya + Founded in 2009, emerya is a human-sized company, dedicated to the design and + implementation of web interfaces. Visit: http://http://emerya.fr/ for more + information. diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml index 93afef0d0..c8369b523 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.info.yml @@ -1,13 +1,15 @@ name: Admin Toolbar -# core: 8.x description: Provides a drop-down menu interface to the core Drupal Toolbar. package: Administration + type: module +# core: 8.x + dependencies: - toolbar -# Information added by Drupal.org packaging script on 2017-09-12 -version: '8.x-1.20' +# Information added by Drupal.org packaging script on 2017-11-20 +version: '8.x-1.21' core: '8.x' project: 'admin_toolbar' -datestamp: 1505199847 +datestamp: 1511190792 diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.module b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.module index 988d173a9..d42df2c12 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.module +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar.module @@ -23,9 +23,15 @@ function admin_toolbar_toolbar_alter(&$items) { function admin_toolbar_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.admin_toolbar': + $variables = [ + ':toolbar' => Url::fromRoute('help.page', ['name' => 'toolbar'])->toString(), + ':automated_cron' => (\Drupal::moduleHandler()->moduleExists('automated_cron')) ? Url::fromRoute('help.page', ['name' => 'automated_cron'])->toString() : '#', + ':admin_toolbar_documentation' => 'https://www.drupal.org/node/2713693', + ]; + $output = ''; $output .= '

' . t('About') . '

'; - $output .= '

' . t('The Admin Toolbar module enhances the Toolbar module by providing fast access to all the administrative links at the top of your site. Admin Toolbar remains a very "lightweight" module by closely integrating with all Toolbar functionality. It can be used in conjunction with all the sub or complimentary modules, listed on Admin Toolbar, for quick access to system commands such as Flush all caches, Run cron, Run Updates, etc... For more information, see the online documentation for the Admin Toolbar module.', [':toolbar' => Url::fromRoute('help.page', ['name' => 'toolbar'])->toString(), ':automated_cron' => (\Drupal::moduleHandler()->moduleExists('automated_cron')) ? Url::fromRoute('help.page', ['name' => 'automated_cron'])->toString() : '#', ':admin_toolbar_documentation' => 'https://www.drupal.org/node/2713693']) . '

'; + $output .= '

' . t('The Admin Toolbar module enhances the Toolbar module by providing fast access to all the administrative links at the top of your site. Admin Toolbar remains a very "lightweight" module by closely integrating with all Toolbar functionality. It can be used in conjunction with all the sub or complimentary modules, listed on Admin Toolbar, for quick access to system commands such as Flush all caches, Run cron, Run Updates, etc... For more information, see the online documentation for the Admin Toolbar module.', $variables) . '

'; $output .= '

' . t('Uses') . '

'; $output .= '

' . t('The Admin Toolbar greatly improves the user experience for those who regularly interact with the Drupal Toolbar by providing fast, full access to all links in the Drupal Toolbar without having to click to get there.') . '

'; @@ -83,7 +89,8 @@ function toolbar_tools_menu_navigation_links(array $tree) { $definition = $link->getPluginDefinition(); $element->options['attributes']['class'][] = 'toolbar-icon'; - $element->options['attributes']['class'][] = 'toolbar-icon-' . strtolower(str_replace(['.', ' ', '_'], ['-', '-', '-'], $definition['id'])); + $string = strtolower(str_replace(['.', ' ', '_'], ['-', '-', '-'], $definition['id'])); + $element->options['attributes']['class'][] = 'toolbar-icon-' . $string; $element->options['attributes']['title'] = $link->getDescription(); } return $tree; diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/README.txt b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/README.txt new file mode 100644 index 000000000..ecd1e4e4b --- /dev/null +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/README.txt @@ -0,0 +1,61 @@ +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Requirements + * Recommended modules + * Installation + * Configuration + * Maintainers + + +INTRODUCTION +------------ + +The Admin Toolbar Links Access Filter module Provides a workaround for the +common problem that users with 'Use the administration pages and help' +permission see menu links they don't have access permission for. Once the issue +https://www.drupal.org/node/296693 be solved, this module will be deprecated. + + * To know why we create this module check this issue: + https://www.drupal.org/node/2917704 + + * To submit bug reports and feature suggestions, or to track changes: + https://www.drupal.org/project/issues/search/admin_toolbar + + +REQUIREMENTS +------------ + +No special requirements. + + +RECOMMENDED MODULES +------------------- + + * Admin Toolbar (https://www.drupal.org/project/admin_toolbar): + Improve the default Drupal Toolbar (the administration menu at the top of + your site) to transform it into a drop-down menu, providing a fast access to + all administration pages. + + +INSTALLATION +------------ + + * Install as you would normally install a contributed Drupal module. + See: https://www.drupal.org/node/895232 for further information. + + +CONFIGURATION +------------- + +No configuration is needed. + + +MAINTAINERS +----------- + +Current maintainers: + * Wilfrid Roze (eme) - https://www.drupal.org/u/eme + * Romain Jarraud (romainj) - https://www.drupal.org/u/romainj + * Adrian Cid Almaguer (adriancid) - https://www.drupal.org/u/adriancid diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.info.yml b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.info.yml new file mode 100644 index 000000000..d5744d559 --- /dev/null +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.info.yml @@ -0,0 +1,12 @@ +name: Admin Toolbar Links Access Filter +description: Provides a workaround for the common problem that users with 'Use the administration pages and help' permission see menu links they don't have access permission for. Once the issue https://www.drupal.org/node/296693 be solved, this module will be deprecated. +package: Administration + +type: module +# core: 8.x + +# Information added by Drupal.org packaging script on 2017-11-20 +version: '8.x-1.21' +core: '8.x' +project: 'admin_toolbar' +datestamp: 1511190792 diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module new file mode 100644 index 000000000..66d5c0d8b --- /dev/null +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module @@ -0,0 +1,176 @@ +getMenuName(); + } + if ($variables['menu_name'] == 'admin') { + if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) { + admin_toolbar_links_access_filter_filter_non_accessible_links($variables['items']); + } + } +} + +/** + * Hides links from admin menu, if user doesn't have access rights. + */ +function admin_toolbar_links_access_filter_filter_non_accessible_links(array &$items) { + foreach ($items as $route => &$item) { + $route_name = $route; + $route_params = []; + if (!empty($item['original_link'])) { + /** @var \Drupal\Core\Menu\MenuLinkBase $original_link */ + $original_link = $item['original_link']; + if ($original_link->getUrlObject()->isExternal()) { + // Do not filter external URL at all. + continue; + } + $route_name = $original_link->getRouteName(); + $route_params = $original_link->getRouteParameters(); + } + + // Check, if user has access rights to the route. + if (!\Drupal::accessManager()->checkNamedRoute($route_name, $route_params)) { + unset($items[$route]); + } + else { + if (!empty($items[$route]['below'])) { + // Recursively call this function for the child items. + admin_toolbar_links_access_filter_filter_non_accessible_links($items[$route]['below']); + } + if (empty($items[$route]['below']) && \Drupal::moduleHandler()->moduleExists('admin_toolbar')) { + + // Every child item has been cleared out. + // Now check, if the given route represents an overview page only, + // without having functionality on its own. In this case, we can safely + // unset this item, as there aren't any children left. + // This assumption is only valid, when the admin_toolbar module is + // installed because otherwise we won't have child items at all. + if (admin_toolbar_links_access_filter_is_overview_page($route)) { + unset($items[$route]); + } + else { + // Let's remove the expanded flag. + $items[$route]['is_expanded'] = FALSE; + } + } + } + } +} + +/** + * Implements template_preprocess_admin_block_content(). + */ +function admin_toolbar_links_access_filter_admin_block_content(&$variables) { + if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) { + foreach ($variables['content'] as $key => &$item) { + if (isset($item['url']) && $item['url'] instanceof Url) { + /* @var \Drupal\Core\Url $url */ + $url = $item['url']; + if ($url->access()) { + continue; + } + unset($variables['content'][$key]); + } + + // The key is structured in the form: "ID title route", + // concatenated with spaces. + $key_parts = explode(' ', $key); + $route = end($key_parts); + + // Special handling for Views pages, as they are not defined + // system routes. + // @TODO check the permission for Views + find a generic way for similar + // cases. Best way would be to get the link entity somehow to properly + // check permissions. + if (strpos($route, 'views_view:') === 0) { + continue; + } + + // Check, if user has access rights to the route. + if (!\Drupal::accessManager()->checkNamedRoute($route)) { + unset($variables['content'][$key]); + } + } + } +} + +/** + * Checks if the given route name is an overview page. + * + * Checks if the given route name matches a pure (admin) overview page that can + * be skipped, if there are no child items set. The typical example are routes + * having the SystemController::systemAdminMenuBlockPage() function as their + * controller callback set. + * + * @param string $route_name + * The route name to check. + * + * @return bool + * TRUE, if the given route name matches a pure admin overview page route, + * FALSE otherwise. + */ +function admin_toolbar_links_access_filter_is_overview_page($route_name) { + // @var \Drupal\Core\Routing\RouteProviderInterface $route_provider. + $route_provider = \Drupal::service('router.route_provider'); + $overview_page_controllers = [ + '\Drupal\system\Controller\AdminController::index', + '\Drupal\system\Controller\SystemController::overview', + '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage', + ]; + try { + $route = $route_provider->getRouteByName($route_name); + $controller = $route->getDefault('_controller'); + return !empty($controller) && in_array($controller, $overview_page_controllers); + } + catch (RouteNotFoundException $ex) { + } + return FALSE; +} + +/** + * Checks, if the given user has admin rights. + * + * @param \Drupal\Core\Session\AccountInterface $account + * The account to check. + * + * @return bool + * TRUE, if the given user account has at least one role with admin rights + * assigned, FALSE otherwise. + */ +function admin_toolbar_links_access_filter_user_has_admin_role(AccountInterface $account) { + foreach ($account->getRoles() as $role_id) { + if (Role::load($role_id)->isAdmin()) { + return TRUE; + } + } + return FALSE; +} diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/README.txt b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/README.txt index c38e5fb2d..4e40e8730 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/README.txt +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/README.txt @@ -1,45 +1,71 @@ ----SUMMARY--- +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Requirements + * Recommended modules + * Installation + * Configuration + * Maintainers + + +INTRODUCTION +------------ Admin Toolbar Extra Tools provides menu links to administration pages or actions (eg. Flushing caches) that are not generated by Drupal core. It adds menu items that are not generated by Drupal core. For example there are no menu items for -each content type by default or menu links to Manage fields on each entity types. -That's the purpose of Admin Toolbar Extra Tools to add them. +each content type by default or menu links to Manage fields on each entity +types. That's the purpose of Admin Toolbar Extra Tools to add them. -For a full description visit project page: -https://www.drupal.org/project/admin_toolbar + * For a full description of the module, visit the project page: + https://www.drupal.org/project/admin_toolbar -Bug reports, feature suggestions and latest developments: -http://drupal.org/project/issues/admin_toolbar + * To submit bug reports and feature suggestions, or to track changes: + https://www.drupal.org/project/issues/search/admin_toolbar ----REQUIREMENTS--- +REQUIREMENTS +------------ -*Admin Toolbar. +This module requires the following modules: + + * Admin Toolbar (https://www.drupal.org/project/admin_toolbar) ----INSTALLATION--- +RECOMMENDED MODULES +------------------- -Install as usual. - -Place the entirety of this directory in the /modules folder of your Drupal -installation. Navigate to Administer > Extend. Check the 'Enabled' box next -'Admin toolbar Extra Tools' and then click the 'Save Configuration' button at -the bottom. - -For help regarding installation, visit: -https://www.drupal.org/documentation/install/modules-themes/modules-8 + * Admin Toolbar (https://www.drupal.org/project/admin_toolbar): + Improve the default Drupal Toolbar (the administration menu at the top of + your site) to transform it into a drop-down menu, providing a fast access to + all administration pages. ----CONTACT--- +INSTALLATION +------------ -Current Maintainers: -*Wilfrid Roze (eme) - https://www.drupal.org/u/eme -*Mohamed Anis Taktak (matio89) - https://www.drupal.org/u/matio89 + * Install as you would normally install a contributed Drupal module. + See: https://www.drupal.org/node/895232 for further information. +CONFIGURATION +------------- + +No configuration is needed. + + +MAINTAINERS +----------- + +Current maintainers: + * Wilfrid Roze (eme) - https://www.drupal.org/u/eme + * Romain Jarraud (romainj) - https://www.drupal.org/u/romainj + * Adrian Cid Almaguer (adriancid) - https://www.drupal.org/u/adriancid + * Mohamed Anis Taktak (matio89) - https://www.drupal.org/u/matio89 + This project has been sponsored by: -*emerya -Founded in 2009, emerya is a human-sized company, dedicated to the design and -implementation of web interfaces. -Visit: http://http://emerya.fr/ for more information. + * emerya + Founded in 2009, emerya is a human-sized company, dedicated to the design and + implementation of web interfaces. Visit: http://http://emerya.fr/ for more + information. diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml index 0af86e101..c1e2bb892 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.info.yml @@ -1,13 +1,15 @@ name: Admin Toolbar Extra Tools -# core: 8.x description: Adds menu links to the Admin Toolbar. package: Administration + type: module +# core: 8.x + dependencies: - admin_toolbar -# Information added by Drupal.org packaging script on 2017-09-12 -version: '8.x-1.20' +# Information added by Drupal.org packaging script on 2017-11-20 +version: '8.x-1.21' core: '8.x' project: 'admin_toolbar' -datestamp: 1505199847 +datestamp: 1511190792 diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.links.menu.yml b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.links.menu.yml index 23d7d1545..69df35f58 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.links.menu.yml +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.links.menu.yml @@ -12,13 +12,6 @@ system.admin_index: parent: admin_toolbar_tools.help weight: -100 -system.run_cron: - title: 'Run cron' - route_name: admin_toolbar.run.cron - menu_name: admin - parent: admin_toolbar_tools.help - weight: -8 - system.db_update: title: 'Run updates' route_name: system.db_update @@ -32,60 +25,23 @@ system.modules_uninstall: menu_name: admin parent: system.modules_list -admin_toolbar_tools.flush: - title: 'Flush all caches' - route_name: admin_toolbar_tools.flush - weight: -9 - parent: admin_toolbar_tools.help - menu_name: admin - -admin_toolbar_tools.cssjs: - title: 'Flush CSS and Javascript' - route_name: admin_toolbar_tools.cssjs - parent: admin_toolbar_tools.flush - menu_name: admin - -admin_toolbar_tools.plugin: - title: 'Flush plugins cache' - route_name: admin_toolbar_tools.plugin - parent: admin_toolbar_tools.flush - menu_name: admin - -admin_toolbar_tools.flush_static: - title: 'Flush static cache' - route_name: admin_toolbar_tools.flush_static - parent: admin_toolbar_tools.flush - menu_name: admin - -admin_toolbar_tools.flush_menu: - title: 'Flush routing and links cache' - route_name: admin_toolbar_tools.flush_menu - parent: admin_toolbar_tools.flush - menu_name: admin - -admin_toolbar_tools.flush_rendercache: - title: 'Flush render cache' - route_name: admin_toolbar_tools.flush_rendercache - parent: admin_toolbar_tools.flush - menu_name: admin - admin_toolbar_tools.drupalorg: title: 'Drupal.org' weight: -5 - route_name: admin_toolbar_tools.drupalorg + url: https://www.drupal.org parent: admin_toolbar_tools.help menu_name: admin admin_toolbar_tools.listchanges: title: 'Change records for Drupal core' weight: -6 - route_name: admin_toolbar_tools.listchanges + url: https://www.drupal.org/list-changes parent: admin_toolbar_tools.drupalorg menu_name: admin admin_toolbar_tools.doc: title: 'D8 API documentation' weight: -5 - route_name: admin_toolbar_tools.doc + url: https://api.drupal.org/api/drupal/8 parent: admin_toolbar_tools.drupalorg menu_name: admin diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module index b48e4f022..40c839ab5 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.module @@ -5,7 +5,9 @@ * Provides extra menu links for the core drupal toolbar. */ +use Drupal\Core\Link; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Url; /** * Implements hook_toolbar(). @@ -26,16 +28,38 @@ function admin_toolbar_tools_toolbar() { return $items; } +/** + * Implements hook_toolbar_alter(). + */ +function admin_toolbar_tools_toolbar_alter(&$items) { + // Use lazybuilder for links so the page is cacheable. + $items['administration']['tray']['toolbar_administration'] = [ + '#lazy_builder' => ['admin_toolbar_tools.toolbar_handler:lazyBuilder', []], + '#create_placeholder' => TRUE, + ]; +} + /** * Implements hook_help(). */ function admin_toolbar_tools_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.admin_toolbar_tools': + $url = Url::fromUri('https://www.drupal.org/project/admin_toolbar'); + $external_link = Link::fromTextAndUrl(t('Admin Toolbar'), $url); + $external_link2 = Link::fromTextAndUrl(t('Toolbar'), $url); + $url = Url::fromUri('https://www.drupal.org/node/2713693'); + $external_link3 = Link::fromTextAndUrl(t('online documentation for Admin Toolbar'), $url); $output = ''; - $output .= '

' . t('The Admin Toolbar Extra Tools module comes packaged with the Admin Toolbar module and adds functionality to it. The additional functionality is accessed thru extra links on the main administration Toolbar. Some links to Admin Toolbar Extra Tools administration pages are located at the bottom of this page. For more information, see the online documentation for Admin Toolbar') . '

'; + $output .= '

'; + $output .= t('The Admin Toolbar Extra Tools module comes packaged with the :link module and adds functionality to it. The additional functionality is accessed thru extra links on the main administration :link2. Some links to Admin Toolbar Extra Tools administration pages are located at the bottom of this page. For more information, see the :link3', [ + ':link' => $external_link, + ':link2' => $external_link2, + ':link3' => $external_link3, + ]); + $output .= '

'; $output .= '

' . t('Uses') . '

'; - $output .= '

' . t('To use Admin Toolbar Extra Tools just install it like any other module. There is no other configuration required. The Admin Toolbar functionality can be further extended by installing complimentary modules. See Admin Toolbar for a complete listing of these complimentary modules.') . '

'; + $output .= '

' . t('To use Admin Toolbar Extra Tools just install it like any other module. There is no other configuration required. The Admin Toolbar functionality can be further extended by installing complimentary modules. See :link for a complete listing of these complimentary modules.', [':link' => $external_link]) . '

'; return $output; } @@ -510,6 +534,97 @@ function admin_toolbar_tools_menu_links_discovered_alter(&$links) { ]; } } + + // Add menu links for local tasks that sit below any admin menu link routes. + $manager = \Drupal::service('plugin.manager.menu.local_task'); + foreach ($links as $key => $link) { + + // Ignore menu links that have no route name or are not in the admin menu. + // @todo Use configuration for admin menu name once added in + // https://www.drupal.org/node/1869638. + if (empty($link['route_name']) || !isset($link['menu_name']) || $link['menu_name'] !== 'admin') { + continue; + } + $route = $link['route_name']; + $route_local_tasks = $manager->getLocalTasksForRoute($route); + if (empty($route_local_tasks[0])) { + continue; + } + + foreach ($route_local_tasks[0] as $plugin_id => $task_plugin) { + $definition = $task_plugin->getPluginDefinition(); + $local_route = $definition['route_name']; + if (empty($local_route)) { + continue; + } + $exists = FALSE; + $param = FALSE; + if (isset($link['route_parameters'])) { + $param = $link['route_parameters']; + } + // Check if local task has an already registered link in toolbar. + foreach ($links as $link2) { + // Route_name that could be a 'class'. + if (!(isset($link2['route_name']) && ($link2['route_name'] == $local_route))) { + continue; + } + // If route are equal, the parameters could be different. + // @todo: check if this is true. + if ($param) { + if (isset($link2['route_parameters']) && ($param == $link2['route_parameters'])) { + $exists = TRUE; + break; + } + } + else { + $exists = TRUE; + break; + } + } + $parent = FALSE; + + if ($exists) { + continue; + } + + $title = $definition['title']; + $title = $param ? $title . ' ' . $link['title'] : $title; + + // The following code is to choose the parent of the added link. + // If the parent of the current tab also has the tab as local task + // for example: "Content" has "File" as task" and and + // "Content>Comment" also has "File" as a tab then we decide to + // set this one as parent of the added link if not the current tab + // will be the parent. + if (!empty($link['parent'])) { + $parentlink = $links[$link['parent']]; + $parentlink_route = $parentlink['route_name']; + $parent_primary = $manager->getLocalTasks($parentlink_route, 0); + foreach ($parent_primary['tabs'] as $parent_tab) { + if ($parent_tab['#link']['url']) { + $parent_route = $parent_tab['#link']['url']->getRouteName(); + if ($parent_route == $local_route) { + $parent = $link['parent']; + break; + } + } + } + } + $parent = $parent ? $parent : $key; + // Make sure the key of the route is unique. + $links[$key . '_' . $local_route] = [ + 'title' => $title, + 'route_name' => $local_route, + 'menu_name' => 'admin', + 'parent' => $parent, + 'att' => TRUE, + ]; + if ($param) { + $links[$key . '_' . $local_route]['route_parameters'] = $param; + } + } + } + } /** diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.routing.yml b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.routing.yml index 5122e4a4b..277808c8e 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.routing.yml +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.routing.yml @@ -6,38 +6,43 @@ admin_toolbar_tools.flush: requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' + admin_toolbar_tools.cssjs: path: '/admin/flush/cssjs' defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flush_js_css' + _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flushJsCss' _title: 'Flush Css and Javascript' requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' + admin_toolbar_tools.plugin: path: '/admin/flush/plugin' defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flush_plugins' + _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flushPlugins' _title: 'Plugin' requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' + admin_toolbar_tools.flush_static: path: '/admin/flush/static-caches' defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flush_static' + _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flushStatic' _title: 'Static caches' requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' + admin_toolbar_tools.flush_menu: path: '/admin/flush/menu' defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flush_menu' + _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flushMenu' _title: 'Menu' requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' + admin_toolbar_tools.flush_rendercache: path: '/admin/flush/rendercache' defaults: @@ -46,38 +51,16 @@ admin_toolbar_tools.flush_rendercache: requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' -admin_toolbar_tools.drupalorg: - path: '/admin/drupal8' + +admin_toolbar_tools.flush_views: + path: '/admin/flush/views' defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::drupal_org' - _title: 'Drupal' - requirements: - _permission: 'access administration pages' - _csrf_token: 'TRUE' -admin_toolbar_tools.listchanges: - path: '/admin/drupal/list-changes' - defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::list_changes' - _title: 'List changes' - requirements: - _permission: 'access administration pages' - _csrf_token: 'TRUE' -admin_toolbar_tools.doc: - path: '/admin/drupal/documentation' - defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::documentation' - _title: 'Documentation D8' - requirements: - _permission: 'access administration pages' - _csrf_token: 'TRUE' -admin_development: - path: '/admin/development' - defaults: - _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::development' - _title: 'Development' + _controller: '\Drupal\admin_toolbar_tools\Controller\ToolbarController::flushViews' + _title: 'Views' requirements: _permission: 'administer site configuration' _csrf_token: 'TRUE' + admin_toolbar.run.cron: path: '/run-cron' defaults: diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.services.yml b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.services.yml new file mode 100644 index 000000000..1343ef7d2 --- /dev/null +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/admin_toolbar_tools.services.yml @@ -0,0 +1,4 @@ +services: + admin_toolbar_tools.toolbar_handler: + class: Drupal\admin_toolbar_tools\ToolbarHandler + arguments: ['@module_handler'] diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php index dc18969dd..b1f275a79 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Controller/ToolbarController.php @@ -2,43 +2,91 @@ namespace Drupal\admin_toolbar_tools\Controller; +use Drupal\Component\Datetime\Time; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\CronInterface; -use Drupal\Core\Routing\TrustedRedirectResponse; -use Drupal\Component\Datetime\Time; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; use Drupal\Core\Menu\ContextualLinkManager; use Drupal\Core\Menu\LocalActionManager; use Drupal\Core\Menu\LocalTaskManager; use Drupal\Core\Menu\MenuLinkManager; +use Drupal\Core\Plugin\CachedDiscoveryClearerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\RequestStack; /** - * Class ToolbarController + * Class ToolbarController. * * @package Drupal\admin_toolbar_tools\Controller */ class ToolbarController extends ControllerBase { /** - * The cron service. + * A cron instance. * - * @var $cron \Drupal\Core\CronInterface + * @var \Drupal\Core\CronInterface */ protected $cron; + + /** + * A menu link manager instance. + * + * @var \Drupal\Core\Menu\MenuLinkManager + */ protected $menuLinkManager; + + /** + * A context link manager instance. + * + * @var \Drupal\Core\Menu\ContextualLinkManager + */ protected $contextualLinkManager; + + /** + * A local task manager instance. + * + * @var \Drupal\Core\Menu\LocalTaskManager + */ protected $localTaskLinkManager; + + /** + * A local action manager instance. + * + * @var \Drupal\Core\Menu\LocalActionManager + */ protected $localActionLinkManager; + + /** + * A cache backend interface instance. + * + * @var \Drupal\Core\Cache\CacheBackendInterface + */ protected $cacheRender; + + /** + * A date time instance. + * + * @var \Drupal\Component\Datetime\Time + */ protected $time; /** - * Constructs a CronController object. + * A request stack symfony instance. * - * @param \Drupal\Core\CronInterface $cron - * The cron service. + * @var \Symfony\Component\HttpFoundation\RequestStack + */ + protected $requestStack; + + /** + * A plugin cache clear instance. + * + * @var \Drupal\Core\Plugin\CachedDiscoveryClearerInterface + */ + protected $pluginCacheClearer; + + /** + * {@inheritdoc} */ public function __construct(CronInterface $cron, MenuLinkManager $menuLinkManager, @@ -46,7 +94,9 @@ class ToolbarController extends ControllerBase { LocalTaskManager $localTaskLinkManager, LocalActionManager $localActionLinkManager, CacheBackendInterface $cacheRender, - Time $time) { + Time $time, + RequestStack $request_stack, + CachedDiscoveryClearerInterface $plugin_cache_clearer) { $this->cron = $cron; $this->menuLinkManager = $menuLinkManager; $this->contextualLinkManager = $contextualLinkManager; @@ -54,6 +104,8 @@ class ToolbarController extends ControllerBase { $this->localActionLinkManager = $localActionLinkManager; $this->cacheRender = $cacheRender; $this->time = $time; + $this->requestStack = $request_stack; + $this->pluginCacheClearer = $plugin_cache_clearer; } /** @@ -67,15 +119,17 @@ class ToolbarController extends ControllerBase { $container->get('plugin.manager.menu.local_task'), $container->get('plugin.manager.menu.local_action'), $container->get('cache.render'), - $container->get('datetime.time') + $container->get('datetime.time'), + $container->get('request_stack'), + $container->get('plugin.cache_clearer') ); } /** * Reload the previous page. */ - public function reload_page() { - $request = \Drupal::request(); + public function reloadPage() { + $request = $this->requestStack->getCurrentRequest(); if ($request->server->get('HTTP_REFERER')) { return $request->server->get('HTTP_REFERER'); } @@ -90,83 +144,57 @@ class ToolbarController extends ControllerBase { public function flushAll() { drupal_flush_all_caches(); drupal_set_message($this->t('All caches cleared.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } /** * Flushes css and javascript caches. */ - public function flush_js_css() { - \Drupal::state() + public function flushJsCss() { + $this->state() ->set('system.css_js_query_string', base_convert($this->time->getCurrentTime(), 10, 36)); drupal_set_message($this->t('CSS and JavaScript cache cleared.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } /** * Flushes plugins caches. */ - public function flush_plugins() { - \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions(); + public function flushPlugins() { + $this->pluginCacheClearer->clearCachedDefinitions(); drupal_set_message($this->t('Plugins cache cleared.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } /** * Resets all static caches. */ - public function flush_static() { + public function flushStatic() { drupal_static_reset(); drupal_set_message($this->t('Static cache cleared.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } /** * Clears all cached menu data. */ - public function flush_menu() { + public function flushMenu() { menu_cache_clear_all(); $this->menuLinkManager->rebuild(); $this->contextualLinkManager->clearCachedDefinitions(); $this->localTaskLinkManager->clearCachedDefinitions(); $this->localActionLinkManager->clearCachedDefinitions(); drupal_set_message($this->t('Routing and links cache cleared.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } /** - * Links to drupal.org home page. + * Clears all cached views data. */ - public function drupal_org() { - $response = new TrustedRedirectResponse("https://www.drupal.org"); - $response->send(); - return $response; - } - - /** - * Displays the administration link Development. - */ - public function development() { - return new RedirectResponse('/admin/structure/menu/'); - } - - /** - * Access to Drupal 8 changes. - * (list changes of the different versions of drupal core). - */ - public function list_changes() { - $response = new TrustedRedirectResponse("https://www.drupal.org/list-changes"); - $response->send(); - return $response; - } - - /** - * Adds a link to the Drupal 8 documentation. - */ - public function documentation() { - $response = new TrustedRedirectResponse("https://api.drupal.org/api/drupal/8"); - $response->send(); - return $response; + public function flushViews() { + views_invalidate_cache(); + drupal_set_message($this->t('Views cache cleared.')); + return new RedirectResponse($this->reloadPage()); } /** @@ -175,7 +203,7 @@ class ToolbarController extends ControllerBase { public function runCron() { $this->cron->run(); drupal_set_message($this->t('Cron ran successfully.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } /** @@ -184,7 +212,7 @@ class ToolbarController extends ControllerBase { public function cacheRender() { $this->cacheRender->invalidateAll(); drupal_set_message($this->t('Render cache cleared.')); - return new RedirectResponse($this->reload_page()); + return new RedirectResponse($this->reloadPage()); } } diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Tests/AdminToolbarToolsAlterTest.php b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Tests/AdminToolbarToolsAlterTest.php index 73035efb1..6c464916e 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Tests/AdminToolbarToolsAlterTest.php +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/Tests/AdminToolbarToolsAlterTest.php @@ -44,7 +44,7 @@ class AdminToolbarToolsAlterTest extends WebTestBase { */ public function testAdminToolbarTools() { // Assert that special menu items are present in the HTML. - $this->assertRaw('class="toolbar-icon toolbar-icon-admin-toolbar-tools-flush"'); + $this->assertRaw('class="toolbar-icon toolbar-icon-admin-toolbar-tools-help"'); } } diff --git a/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/ToolbarHandler.php b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/ToolbarHandler.php new file mode 100644 index 000000000..58a548b24 --- /dev/null +++ b/sites/all/modules/contrib/admin/admin_toolbar/admin_toolbar_tools/src/ToolbarHandler.php @@ -0,0 +1,135 @@ +moduleHandler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('module_handler') + ); + } + + /** + * Lazy builder callback for the admin_toolbar_tool items. + * + * @return array + * A renderable array as expected by the renderer service. + */ + public function lazyBuilder() { + // Render the pre_render callback we disabled earlier. + $build = admin_toolbar_prerender_toolbar_administration_tray([]); + + // Add links that are uncacheable. + // Core toolbar module calculates cachability in advance so we have to build + // a fake menu tree here, including access checks. + $tools_menu = &$build['administration_menu']['#items']['admin_toolbar_tools.help']['below']; + + // Adding the 'Flush all caches' menu in the correct place. + $menu_render_array = $this->createMenuRenderArray('admin_toolbar_tools.flush', $this->t('Flush all caches'), TRUE); + $this->arrayInsert($tools_menu, 1, $menu_render_array); + + // Adding the submenus to 'Flush all caches' menu. + if (!empty($tools_menu['admin_toolbar_tools.flush'])) { + $tools_sub_menu = &$tools_menu['admin_toolbar_tools.flush']['below']; + $tools_sub_menu += $this->createMenuRenderArray('admin_toolbar_tools.cssjs', $this->t('Flush CSS and Javascript')); + $tools_sub_menu += $this->createMenuRenderArray('admin_toolbar_tools.plugin', $this->t('Flush plugins cache')); + $tools_sub_menu += $this->createMenuRenderArray('admin_toolbar_tools.flush_static', $this->t('Flush static cache')); + $tools_sub_menu += $this->createMenuRenderArray('admin_toolbar_tools.flush_menu', $this->t('Flush routing and links cache')); + $tools_sub_menu += $this->createMenuRenderArray('admin_toolbar_tools.flush_rendercache', $this->t('Flush render cache')); + + // Adding a menu link to clean the Views cache. + if ($this->moduleHandler->moduleExists('views')) { + $tools_sub_menu += $this->createMenuRenderArray('admin_toolbar_tools.flush_views', $this->t('Flush views cache')); + } + } + + // Adding the 'Run Cron' menu in the correct place. + $menu_render_array = $this->createMenuRenderArray('system.run_cron', $this->t('Run cron')); + $this->arrayInsert($tools_menu, 3, $menu_render_array); + + return $build; + } + + /** + * Create the menu render array. + * + * @param string $route + * The route. + * @param string $title + * The menu title. + * @param bool $submenu + * Specify if the current menu element have a submenu. + * + * @return array + * A renderable array as expected by the renderer service. + */ + private function createMenuRenderArray($route, $title, $submenu = FALSE) { + $data = []; + $url = Url::fromRoute($route); + if ($url->access()) { + $data[$route] = [ + 'title' => $title, + 'url' => $url, + 'attributes' => new Attribute(['class' => ['menu-item'] + ($submenu ? ['menu-item--expanded'] : [])]), + ]; + if ($submenu) { + $data[$route]['below'] = []; + $data[$route]['is_expanded'] = TRUE; + } + } + return $data; + } + + /** + * Insert an array in a given position of another array. + * + * @param array $array + * The array where we need to insert new elements. + * @param int $position + * The position where we will add the new array. + * @param array $insert_array + * The array that will be inserted. + * + * @see http://php.net/manual/en/function.array-splice.php#56794 + */ + private function arrayInsert(array &$array, $position, array $insert_array) { + // Getting the first part of the array. + $first_array = array_splice($array, 0, $position); + // Inserting the new part in the desired position. + $array = array_merge($first_array, $insert_array, $array); + } + +} diff --git a/sites/all/modules/contrib/admin/admin_toolbar/css/admin.toolbar.css b/sites/all/modules/contrib/admin/admin_toolbar/css/admin.toolbar.css index f1651b0b3..ecac624cb 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/css/admin.toolbar.css +++ b/sites/all/modules/contrib/admin/admin_toolbar/css/admin.toolbar.css @@ -1,15 +1,18 @@ /*---------------------- menu horizontal hover---- Krout Fethi FrontEnd Developer-----*/ -#toolbar-bar { - z-index: 9999; -} .toolbar-tray-horizontal .menu-item:hover { background: #fff; } -.toolbar-tray-horizontal .menu-item:focus { +.toolbar-tray-horizontal .menu-item a:focus { background: #abeae4; } +.toolbar-tray-horizontal .toolbar-menu:not(:first-child) li.menu-item--expanded > a:focus { + background-position: center right; + background-image: url('../misc/icons/0074bd/chevron-right.svg'); + background-repeat: no-repeat; +} + .toolbar-tray-horizontal .menu-item--expanded .menu { background: #fff; width: auto; @@ -82,6 +85,10 @@ margin: -40px 0 0 197px; } +.toolbar-tray-horizontal li:hover ul li { + float: none; +} + .toolbar-tray-horizontal li.hover-intent ul li { float: none; } @@ -110,6 +117,10 @@ float: none !important; } +[dir="rtl"] .toolbar-tray-horizontal li:focus ul li { + float: none !important; +} + [dir="rtl"] .toolbar .toolbar-menu ul .toolbar-icon { padding-left: 1.3333em; } @@ -118,6 +129,10 @@ margin: -40px 197px 0 0; } +[dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded .menu-item:focus ul { + margin: -40px 197px 0 0; +} + [dir="rtl"] .toolbar-tray-horizontal ul li.menu-item--expanded ul li.menu-item--expanded { background-position: center left; background-image: url('../misc/icons/0074bd/chevron-left.svg'); diff --git a/sites/all/modules/contrib/admin/admin_toolbar/js/admin_toolbar.js b/sites/all/modules/contrib/admin/admin_toolbar/js/admin_toolbar.js index 51032ee8b..588eb812b 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/js/admin_toolbar.js +++ b/sites/all/modules/contrib/admin/admin_toolbar/js/admin_toolbar.js @@ -12,7 +12,39 @@ out: function () { $(this).removeClass('hover-intent'); }, - timeout: 500 + timeout: 250 }); + + // Make the toolbar menu navigable with keyboard. + $('ul.toolbar-menu li.menu-item--expanded a').on('focusin', function () { + $('li.menu-item--expanded').removeClass('hover-intent'); + $(this).parents('li.menu-item--expanded').addClass('hover-intent'); + }); + + $('ul.toolbar-menu li.menu-item a').keydown(function (e) { + if ((e.shiftKey && (e.keyCode || e.which) == 9)) { + if ($(this).parent('.menu-item').prev().hasClass('menu-item--expanded')) { + $(this).parent('.menu-item').prev().addClass('hover-intent'); + } + } + }); + + $('.toolbar-menu:first-child > .menu-item:not(.menu-item--expanded) a, .toolbar-tab > a').on('focusin', function () { + $('.menu-item--expanded').removeClass('hover-intent'); + }); + + $('.toolbar-menu:first-child > .menu-item').on('hover', function () { + $(this,'a').css("background: #fff;"); + }); + + $('ul:not(.toolbar-menu)').on({ + mousemove: function () { + $('li.menu-item--expanded').removeClass('hover-intent'); + }, + hover: function () { + $('li.menu-item--expanded').removeClass('hover-intent'); + } + }); + }); })(jQuery); diff --git a/sites/all/modules/contrib/admin/admin_toolbar/src/Tests/AdminToolbarAlterTest.php b/sites/all/modules/contrib/admin/admin_toolbar/src/Tests/AdminToolbarAlterTest.php index 11cdc0fff..d4f41ace3 100644 --- a/sites/all/modules/contrib/admin/admin_toolbar/src/Tests/AdminToolbarAlterTest.php +++ b/sites/all/modules/contrib/admin/admin_toolbar/src/Tests/AdminToolbarAlterTest.php @@ -4,7 +4,6 @@ namespace Drupal\admin_toolbar\Tests; use Drupal\simpletest\WebTestBase; - /** * Test the existence of Admin Toolbar module. * @@ -43,8 +42,9 @@ class AdminToolbarAlterTest extends WebTestBase { /** * Tests for a the hover of sub menus. */ - function testAdminToolbar() { + public function testAdminToolbar() { // Assert that expanded links are present in the HTML. $this->assertRaw('class="toolbar-icon toolbar-icon-user-admin-index"'); } + } diff --git a/sites/all/modules/contrib/dev/config_devel/config_devel.info.yml b/sites/all/modules/contrib/dev/config_devel/config_devel.info.yml index 142b8eb70..7a471b680 100644 --- a/sites/all/modules/contrib/dev/config_devel/config_devel.info.yml +++ b/sites/all/modules/contrib/dev/config_devel/config_devel.info.yml @@ -6,8 +6,8 @@ package: Configuration # core: 8.x configure: config_devel.settings -# Information added by Drupal.org packaging script on 2017-09-11 -version: '8.x-1.1' +# Information added by Drupal.org packaging script on 2017-11-16 +version: '8.x-1.2' core: '8.x' project: 'config_devel' -datestamp: 1505141047 +datestamp: 1510843086 diff --git a/sites/all/modules/contrib/dev/config_devel/drush.services.yml b/sites/all/modules/contrib/dev/config_devel/drush.services.yml new file mode 100644 index 000000000..5d75b380d --- /dev/null +++ b/sites/all/modules/contrib/dev/config_devel/drush.services.yml @@ -0,0 +1,13 @@ +services: + config_devel.commands: + class: \Drupal\config_devel\Commands\ConfigDevelCommands + arguments: + - '@module_handler' + - '@theme_handler' + - '@info_parser' + - '@config.factory' + - '@config_devel.writeback_subscriber' + - '@config_devel.auto_import_subscriber' + - '@file_system' + tags: + - { name: drush.command } diff --git a/sites/all/modules/contrib/dev/config_devel/drush/config_devel.drush.inc b/sites/all/modules/contrib/dev/config_devel/drush/config_devel.drush.inc index 143edaf0f..fc3244abd 100644 --- a/sites/all/modules/contrib/dev/config_devel/drush/config_devel.drush.inc +++ b/sites/all/modules/contrib/dev/config_devel/drush/config_devel.drush.inc @@ -156,15 +156,27 @@ function drush_config_devel_import_one($path) { * The module, theme or install profile we're exporting. * @param string $directory * The directory we're exporting to. + * + * @return bool + * TRUE when the configuration was successfully exported. FALSE otherwise. */ function drush_config_devel_process_config($config_list, $type, $extension, $directory) { $config_path = drupal_get_path($type, $extension) . "/$directory"; + + // Ensure the directory always exists. + if (!file_exists($config_path) && !\Drupal::service('file_system')->mkdir($config_path, NULL, TRUE)) { + drush_set_error('CONFIG_DEVEL_DIRECTORY_NOT_CREATED', sprintf('The %s directory could not be created', $config_path)); + return FALSE; + } + foreach ($config_list as $name) { $config = \Drupal::config($name); $file_names = array($config_path . '/' . $name . '.yml'); \Drupal::service('config_devel.writeback_subscriber')->writeBackConfig($config, $file_names); } + + return TRUE; } /** diff --git a/sites/all/modules/contrib/dev/config_devel/src/Commands/ConfigDevelCommands.php b/sites/all/modules/contrib/dev/config_devel/src/Commands/ConfigDevelCommands.php new file mode 100644 index 000000000..8d074d181 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_devel/src/Commands/ConfigDevelCommands.php @@ -0,0 +1,353 @@ +moduleHandler = $moduleHandler; + $this->themeHandler = $themeHandler; + $this->infoParser = $infoParser; + $this->configFactory = $configFactory; + // @todo We should not depend on event subscribers directly. + // @see https://www.drupal.org/node/2388253 + $this->autoExportSubscriber = $autoExportSubscriber; + $this->autoImportSubscriber = $autoImportSubscriber; + $this->fileSystem = $fileSystem; + } + + /** + * Write back configuration to module's config directory. + * + * List which configuration settings you want to export in the module's info + * file by listing them under 'config_devel', as shown below: + * + * config_devel: + * install: + * - entity.view_display.node.article.default + * - entity.view_display.node.article.teaser + * - field.instance.node.article.body + * optional: + * - field.instance.node.article.tags + * + * @command config-devel-export + * @param string $extension Machine name of the module, profile or theme to export. + * @usage drush config-devel-export MODULE_NAME + * Write back configuration to the specified module, based on .info file. + * @aliases cde,cd-em + * + * @throws \Exception + * Thrown when the passed in extension + */ + public function export($extension) { + // Determine the type of extension we're dealing with. + $type = $this->getExtensionType($extension); + + if (!$type) { + throw new \Exception("Couldn't export configuration. The '$extension' extension is not enabled."); + } + + // Get the config. + $config = $this->getExtensionConfig($type, $extension); + + // Export the required config. + if (isset($config['install'])) { + $this->exportConfig($config['install'], $type, $extension, InstallStorage::CONFIG_INSTALL_DIRECTORY); + } + + // If we have any optional configuration, export that as well. + if (isset($config['optional'])) { + $this->exportConfig($config['optional'], $type, $extension, InstallStorage::CONFIG_OPTIONAL_DIRECTORY); + } + } + + /** + * Import configuration from module's config directory to active storage. + * + * List which configuration settings you want to export in the module's info + * file by listing them under 'config_devel', as shown below: + * + * config_devel: + * install: + * - entity.view_display.node.article.default + * - entity.view_display.node.article.teaser + * - field.instance.node.article.body + * optional: + * - field.instance.node.article.tags + * + * @command config-devel-import + * @param string $extension Machine name of the module, profile or theme. + * @usage drush config-devel-import MODULE_NAME + * Import configuration from the specified module, profile or theme into the active storage, based on .info file. + * @aliases cdi,cd-im + * + * @throws \Exception + * Thrown when the passed in extension is not enabled. + */ + public function import($extension) { + // Determine the type of extension we're dealing with. + $type = $this->getExtensionType($extension); + + if (!$type) { + throw new \Exception("Couldn't import configuration. The '$extension' extension is not enabled."); + } + + // Get the config + $config = $this->getExtensionConfig($type, $extension); + + // Import config + if (isset($config['install'])) { + $this->importConfig($config['install'], $type, $extension, InstallStorage::CONFIG_INSTALL_DIRECTORY); + } + + // Import optional config + if (isset($config['optional'])) { + $this->importConfig($config['optional'], $type, $extension, InstallStorage::CONFIG_OPTIONAL_DIRECTORY); + } + } + + /** + * Import a single config item into active storage. + * + * List which configuration settings you want to export in the module's info + * file by listing them under 'config_devel', as shown below: + * + * config_devel: + * install: + * - entity.view_display.node.article.default + * - entity.view_display.node.article.teaser + * - field.instance.node.article.body + * optional: + * - field.instance.node.article.tags + * + * @command config-devel-import-one + * @param string $path Config file name. + * @usage drush config-devel-import-one system.site.yml + * Import the contents of system.site.yml into the config object system.site. + * @usage drush config-devel-import-one system.site + * Import the standard input into the config object system.site. Helpful for scripting copying to remote. + * @aliases cdi1,cd-i1 + * + * @throws \Exception + * Thrown when the given file was not found. + */ + public function importSingle($path) { + $contents = ''; + if (!file_exists($path)) { + if (substr($path, -4) != '.yml') { + $contents = file_get_contents('php://stdin'); + } + elseif (!empty($_SERVER['PWD'])) { + $path = $_SERVER['PWD'] . '/' . trim($path, '/'); + } + } + if ($contents || file_exists($path)) { + $this->autoImportSubscriber->importOne($path, '', $contents); + } + else { + throw new \Exception("File '$path' not found."); + } + } + + /** + * Returns the type for the given extension. + * + * @param string $extension + * The extension name. + * + * @return string + * Either 'module', 'theme', 'profile', or NULL if no valid extension was + * provided. + */ + protected function getExtensionType($extension) { + $type = NULL; + + if ($this->moduleHandler->moduleExists($extension)) { + $type = 'module'; + } + elseif ($this->themeHandler->themeExists($extension)) { + $type = 'theme'; + } + elseif (\Drupal::installProfile() === $extension) { + $type = 'profile'; + } + + return $type; + } + + /** + * Returns the config for the given extension. + * + * @param string $type + * Either 'module', 'theme' or 'profile'. + * @param string $extension + * The name of the extension for which to return the config. + * + * @return array + * An array containing install and optional config. + */ + protected function getExtensionConfig($type, $extension) { + $filename = drupal_get_path($type, $extension) . '/' . $extension .'.info.yml'; + $info = $this->infoParser->parse($filename); + + $config = []; + if (isset($info['config_devel'])) { + // Keep backwards compatibility for the old format. This has config names + // listed directly beneath 'config_devel', rather than an intermediate + // level for 'install' and 'optional'. + // Detect the old format based on whether there's neither of these two + // keys. + if (!isset($info['config_devel']['install']) && !isset($info['config_devel']['optional'])) { + $info['config_devel']['install'] = $info['config_devel']; + } + + $config['install'] = $info['config_devel']['install']; + + // If we have any optional configuration, fetch that as well. + if (isset($info['config_devel']['optional'])) { + $config['optional'] = $info['config_devel']['optional']; + } + } + + return $config; + } + + /** + * Exports a list of configuration entities. + * + * @param array $config_list + * An array of configuration entities. + * @param string $type + * The type of extension we're exporting, one of 'module', 'profile' or + * 'theme'. + * @param string $extension + * The name of the extension we're exporting. + * @param string $directory + * The directory we're exporting to. + * + * @throws \Exception + * Thrown when the directory to export to is missing and could not be + * created. + */ + protected function exportConfig($config_list, $type, $extension, $directory) { + $config_path = drupal_get_path($type, $extension) . "/$directory"; + // Ensure the directory always exists. + if (!file_exists($config_path) && !$this->fileSystem->mkdir($config_path, NULL, TRUE)) { + throw new \Exception(sprintf('The %s directory could not be created', $config_path)); + } + + foreach ($config_list as $name) { + $config = $this->configFactory->get($name); + $file_names = [$config_path . '/' . $name . '.yml']; + $this->autoExportSubscriber->writeBackConfig($config, $file_names); + } + } + + /** + * Imports a list of configuration entities. + * + * @param array $config_list + * An array of configuration entities. + * @param string $type + * The type of extension we're importing, one of 'module'. 'profile' or + * 'theme'. + * @param string $extension + * The module, theme or install profile we're importing. + * @param string $directory + * The directory we're importing. + */ + protected function importConfig($config_list, $type, $extension, $directory) { + $config_path = drupal_get_path($type, $extension) . "/$directory"; + foreach ($config_list as $name) { + $file_name = $config_path . '/' . $name . '.yml'; + $this->importSingle($file_name); + } + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/LICENSE.txt b/sites/all/modules/contrib/migrate/migrate_plus/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/migrate/migrate_plus/README.txt b/sites/all/modules/contrib/migrate/migrate_plus/README.txt new file mode 100644 index 000000000..797082e38 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/README.txt @@ -0,0 +1,77 @@ +The migrate_plus module extends the core migration system with API enhancements +and additional functionality, as well as providing practical examples. + +Extensions to base API +====================== +* A Migration configuration entity is provided, enabling persistance of dynamic + migration configuration. +* A MigrationGroup configuration entity is provided, which enables migrations to + be organized in groups, and to maintain shared configuration in one place. +* A MigrateEvents::PREPARE_ROW event is provided to dispatch hook_prepare_row() + invocations as events. +* A SourcePluginExtension class is provided, enabling one to define fields and + IDs for a source plugin via configuration rather than requiring PHP code. + +Plugin types +============ +migrate_plus provides the following plugin types, for use with the url source +plugin. + +* A data_parser type, for parsing different formats on behalf of the url source + plugin. +* A data_fetcher type, for fetching data to feed into a data_parser plugin. +* An authentication type, for adding authentication headers with the http + data_fetcher plugin. + +Plugins +======= + +Process +------- +* The entity_lookup process plugin allows you to populate references to entities + which already exist in Drupal, whether they were migrated or not. +* The entity_generate process plugin extends entity_lookup to also create the + desired entity when it doesn't already exist. +* The file_blob process plugin supports creating file entities from blob data. +* The merge process plugin allows the merging of multiple arrays into a single + field. +* The skip_on_value process plugin allows you to skip a row, or a given field, + for specific source values. + +Source +------ +* A url source plugin is provided, implementing a common structure for + file-based data providers. + +Data parsers +------------ +* The xml parser plugin uses PHP's XMLReader interface to incrementally parse + XML files. This should be used for XML sources which are potentially very + large. +* The simple_xml parser plugin uses PHP's SimpleXML interface to fully parse + XML files. This should be used for XML sources where you need to be able to + use complex xpaths for your item selectors, or have to access elements outside + of the current item element via xpaths. +* The json parser plugin supports JSON sources. +* The soap parser plugin supports SOAP sources. + +Data fetchers +------------- +* The file fetcher plugin works for most URLs regardless of protocol, as well as + local filesystems. +* The http fetcher plugin provides the ability to add headers to an HTTP + request (particularly through authentication plugins). + +Authentication +-------------- +* The basic authentication plugin provides HTTP Basic authentication. +* The digest authentication plugin provides HTTP Digest authentication. +* The oauth2 authentication plugin provides OAuth2 authentication over HTTP. + +Examples +======== +* The migrate_example submodule provides a fully functional and runnable +example migration scenario demonstrating the basic concepts and most common +techniques for SQL-based migrations. +* The migrate_example_advanced submodule provides examples of migration from +different kinds of sources, as well as less common techniques. diff --git a/sites/all/modules/contrib/migrate/migrate_plus/composer.json b/sites/all/modules/contrib/migrate/migrate_plus/composer.json new file mode 100644 index 000000000..b1dbd8570 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/composer.json @@ -0,0 +1,24 @@ +{ + "name": "drupal/migrate_plus", + "description": "Enhancements to core migration support.", + "type": "drupal-module", + "license": "GPL-2.0+", + "homepage": "https://www.drupal.org/project/migrate_plus", + "authors": [ + { + "name": "Mike Ryan", + "homepage":"https://www.drupal.org/u/mikeryan", + "role": "Maintainer" + } + ], + "support": { + "issues": "https://www.drupal.org/project/issues/migrate_plus", + "irc": "irc://irc.freenode.org/drupal-migrate", + "source": "https://cgit.drupalcode.org/migrate_plus" + }, + "minimum-stability": "dev", + "require": {}, + "suggest": { + "sainsburys/guzzle-oauth2-plugin": "3.0 required for the OAuth2 authentication plugin" + } +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.data_types.schema.yml b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.data_types.schema.yml new file mode 100644 index 000000000..27c8006f4 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.data_types.schema.yml @@ -0,0 +1,40 @@ +# Basic data types for Migrate. + +migrate_plugin: + type: mapping + mapping: + plugin: + type: string + label: 'Plugin' + +migrate_destination: + type: migrate_plugin + label: 'Destination' + mapping: + overwrite_properties: + type: sequence + label: 'Properties to overwrite' + sequence: + type: string + label: 'Property' + +migrate_source: + type: migrate_plugin + label: 'Source' + mapping: + constants: + type: ignore + label: 'Constants' + +migrate_process: + type: migrate_plugin + label: 'Process' + +# Base schema for migrate source plugins that extend +# \Drupal\migrate\Plugin\migrate\source\SqlBase. +migrate_source_sql: + type: migrate_source + mapping: + target: + type: string + label: 'The migration database target' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.destination.schema.yml b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.destination.schema.yml new file mode 100644 index 000000000..58ad74e53 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.destination.schema.yml @@ -0,0 +1,18 @@ +# Schema for the migrate destination plugins. + +migrate_plus.destination.*: + type: migrate_destination + label: 'Default destination' + mapping: + no_stub: + type: boolean + label: 'Whether stubbing is allowed.' + default: false + +migrate_plus.destination.config: + type: migrate_destination + label: 'Config' + mapping: + config_name: + type: string + label: 'Configuration name' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.process.schema.yml b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.process.schema.yml new file mode 100644 index 000000000..b1f123bc3 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.process.schema.yml @@ -0,0 +1,145 @@ +# Schema for the migrate process plugins. + +migrate_plus.process.*: + type: migrate_process + label: 'Default process' + +migrate_plus.process.callback: + type: migrate_process + label: 'Callback process' + mapping: + callback: + type: string + label: 'Callback' + +migrate_plus.process.concat: + type: migrate_process + label: 'Concat process' + mapping: + delimiter: + type: string + label: 'Delimiter' + +migrate_plus.process.dedupe_entity: + type: migrate_process + label: 'Dedupe Entity process' + mapping: + entity_type: + type: string + label: 'Entity type' + field: + type: string + label: 'Field name' + postfix: + type: string + label: 'Postfix' + start: + type: integer + label: 'Start' + length: + type: integer + label: 'Length' + +migrate_plus.process.explode: + type: migrate_process + label: 'Explode process' + mapping: + delimiter: + type: string + label: 'Delimiter' + limit: + type: integer + label: 'Limit' + +migrate_plus.process.extract: + type: migrate_process + label: 'Extract process' + mapping: + default: + type: string + label: 'Default value' + +migrate_plus.process.flatten: + type: migrate_process + label: 'Flatten process' + +migrate_plus.process.get: + type: migrate_process + label: 'Get process' + mapping: + source: + type: string + label: 'Source key' + +migrate_plus.process.iterator: + type: migrate_process + label: 'Iterator process' + mapping: + process: + type: ignore + label: 'Process' + key: + type: string + label: 'Key' + +migrate_plus.process.machine_name: + type: migrate_process + label: 'Machine name process' + +migrate_plus.process.migration: + type: migrate_process + label: 'Migration process' + mapping: + migration: + type: sequence + label: 'Migration' + source: + type: sequence + label: 'Source keys' + source_ids: + type: string + label: 'Source IDs' + stub_id: + type: string + label: 'Stub ID' + +migrate_plus.process.route: + type: migrate_process + label: 'Route process' + +migrate_plus.process.skip_on_empty: + type: migrate_process + label: 'Skip on Empty' + +migrate_plus.process.skip_row_if_not_set: + type: migrate_process + label: 'Skip Row process if not set' + mapping: + index: + type: integer + label: 'Index' + +migrate_plus.process.static_map: + type: migrate_process + label: 'Static Map' + mapping: + map: + type: sequence + label: 'Map' + default_value: + type: string + label: 'Default value' + bypass: + type: boolean + label: 'Bypass lookup' + +migrate_plus.process.default_value: + type: migrate_process + label: 'Default value' + mapping: + strict: + type: boolean + label: 'Strict type check' + default_value: + type: string + label: 'Default value' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.schema.yml b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.schema.yml new file mode 100644 index 000000000..99aef5523 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.schema.yml @@ -0,0 +1,78 @@ +# Schema for the configuration files of the Migrate Plus module. + +migrate_plus.migration.*: + type: config_entity + label: 'Migration' + mapping: + id: + type: string + label: 'ID' + class: + type: string + label: 'Class' + field_plugin_method: + type: string + label: 'Field Plugin Method' + cck_plugin_method: + type: string + label: 'BC layer for Field Plugin Method' + migration_tags: + type: sequence + label: 'Migration Tags' + sequence: + type: string + label: 'Tag' + migration_group: + type: string + label: 'Group' + label: + type: label + label: 'Label' + source: + type: migrate_plus.source.[plugin] + label: 'Source' + process: + type: ignore + label: 'Process' + destination: + type: migrate_plus.destination.[plugin] + label: 'Destination' + migration_dependencies: + type: mapping + label: 'Dependencies' + mapping: + required: + type: sequence + label: 'Required dependencies' + sequence: + type: string + label: 'Dependency' + optional: + type: sequence + label: 'Optional dependencies' + sequence: + type: string + label: 'Dependency' + +migrate_plus.migration_group.*: + type: config_entity + label: 'Migration Group' + mapping: + id: + type: string + label: 'ID' + label: + type: label + label: 'Label' + description: + type: string + label: 'Description' + source_type: + type: string + label: 'Source type' + module: + type: string + label: 'Dependent module' + shared_configuration: + type: ignore + label: 'Shared migration configuration' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.source.schema.yml b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.source.schema.yml new file mode 100644 index 000000000..4117ea410 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/config/schema/migrate_plus.source.schema.yml @@ -0,0 +1,34 @@ +# Schema for the migrate source plugins. + +migrate_plus.source.*: + type: migrate_source + label: 'Default source' + +migrate_plus.source.empty: + type: migrate_source_sql + label: 'Empty source' + mapping: + provider: + type: string + label: 'Provider' + +migrate_plus.source.embedded_data: + type: migrate_source + label: 'Embedded data source' + mapping: + data_rows: + type: sequence + label: 'Data rows' + sequence: + type: ignore + label: 'Data row' + ids: + type: sequence + label: 'Unique key' + sequence: + type: mapping + label: 'Key column' + mapping: + type: + type: string + label: 'Column type' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/README.txt b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/README.txt new file mode 100644 index 000000000..32d77da99 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/README.txt @@ -0,0 +1,111 @@ +INTRODUCTION +------------ +The migrate_example module demonstrates how to implement custom migrations +for Drupal 8. It includes a group of "beer" migrations demonstrating a complete +simple migration scenario. + +THE BEER SITE +------------- +In this scenario, we have a beer aficionado site which stores its data in MySQL +tables - there are content items for each beer on the site, user accounts with +profile data, categories to classify the beers, and user-generated comments on +the beers. We want to convert this site to Drupal with just a few modifications +to the basic structure. + +To make the example as simple as to run as possible, the source data is placed +in tables directly in your Drupal database - in most real-world scenarios, your +source data will be in an external database. The migrate_example_setup submodule +creates and populates these tables, as well as configuring your Drupal 8 site +(creating a node type, vocabulary, fields, etc.) to receive the data. + +STRUCTURE +--------- +There are two primary components to this example: + +1. Migration configuration, in the migrations and config/install directories. + These YAML files describe the migration process and provide the mappings from + the source data to Drupal's destination entities. The difference between the + two possible directories: + + a. Files in the migrations directory provide configuration directly for the + migration plugins. The filenames are of the form .yml. This + approach is recommended when your migration configuration is fully hardcoded + and does not need to be overridden (e.g., you don't need to change the URL to + a source web service through an admin UI). While developing migrations, + changes to these files require at most a 'drush cr' to load your changes. + + b. Files in the config/install directory provide migration configuration as + configuration entities, and have names of the form + migrate_plus.migration..yml ("migration" because they define + entities of the "migration" type, and "migrate_plus" because that is the + module which implements the "migration" type). Migrations defined in this way + may have their configuration modified (in particular, through a web UI) by + loading the configuration entity, modifying its configuration, and saving the + entity. When developing, to get edits to the .yml files in config/install to + take effect in active configuration, use the config_devel module. + + Configuration in either type of file is identical - the only differences are + the directories and filenames. + +2. Source plugins, in src/Plugin/migrate/source. These are referenced from the + configuration files, and provide the source data to the migration processing + pipeline, as well as manipulating that data where necessary to put it into + a canonical form for migrations. + +UNDERSTANDING THE MIGRATIONS +---------------------------- +The YAML and PHP files are copiously documented in-line. To best understand +the concepts described in a more-or-less narrative form, it is recommended you +read the files in the following order: + +1. migrate_plus.migration_group.beer.yml +2. migrate_plus.migration.beer_term.yml +3. BeerTerm.php +4. migrate_plus.migration.beer_user.yml +5. BeerUser.php +6. migrate_plus.migration.beer_node.yml +7. BeerNode.php +8. migrate_plus.migration.beer_comment.yml +9. BeerComment.php + +RUNNING THE MIGRATIONS +---------------------- +The migrate_tools module (https://www.drupal.org/project/migrate_tools) provides +the tools you need to perform migration processes. At this time, the web UI only +provides status information - to perform migration operations, you need to use +the drush commands. + +# Enable the tools and the example module if you haven't already. +drush en -y migrate_tools,migrate_example + +# Look at the migrations. Just look at them. Notice that they are displayed in +# the order they will be run, which reflects their dependencies. For example, +# because the node migration references the imported terms and users, it must +# run after those migrations have been run. +drush ms # Abbreviation for migrate-status + +# Run the import operation for all the beer migrations. +drush mi --group=beer # Abbreviation for migrate-import + +# Look at what you've done! Also, visit the site and see the imported content, +# user accounts, etc. +drush ms + +# Look at the duplicate username message. +drush mmsg beer_user # Abbreviation for migrate-messages + +# Run the rollback operation for all the migrations (removing all the imported +# content, user accounts, etc.). Note that it will rollback the migrations in +# the opposite order as they were imported. +drush mr --group=beer # Abbreviation for migrate-rollback + +# You can import specific migrations. +drush mi beer_term,beer_user +# At this point, go look at your content listing - you'll see beer nodes named +# "Stub", generated from the user's favbeers references. + +drush mi beer_node,beer_comment +# Refresh your content listing - the stub nodes have been filled with real beer! + +# You can rollback specific migrations. +drush mr beer_comment,beer_node diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_node.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_node.yml new file mode 100644 index 000000000..e2a9aefcb --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_node.yml @@ -0,0 +1,53 @@ +# Migration configuration for beer content. +id: beer_node +label: Beers of the world +migration_group: beer +source: + plugin: beer_node +destination: + plugin: entity:node +process: + # Hardcode the destination node type (bundle) as 'migrate_example_beer'. + type: + plugin: default_value + default_value: migrate_example_beer + title: name + nid: bid + uid: + plugin: migration + migration: beer_user + source: aid + sticky: + plugin: default_value + default_value: 0 + field_migrate_example_country: countries + field_migrate_example_beer_style: + plugin: migration + migration: beer_term + source: terms + # Some Drupal fields may have multiple components we may want to set + # separately. For example, text fields may have summaries (teasers) in + # addition to the full text value. We use / to separate the field name from + # the internal field value being set, and put it in quotes because / is a + # YAML special character. + 'body/value': body + 'body/summary': excerpt +# Our beer nodes have references to terms and users, so we want those to be +# imported first. We make that dependency explicit here - by putting those +# migrations under the 'required' key, we ensure that the tools will prevent +# us from running the beer_node migration unless the beer_term and beer_user +# migrations are complete (although we can override the dependency check by +# passing --force to the drush migrate-import command). We can also add +# 'optional' dependencies - these affect the order in which migrations are +# displayed, and run by default, but does not force you run them in that +# order. +# The general rule of thumb is that any migrations referenced by migration +# process plugins should be required here. +migration_dependencies: + required: + - beer_term + - beer_user +dependencies: + enforced: + module: + - migrate_example diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_term.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_term.yml new file mode 100644 index 000000000..a7ca1858c --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_term.yml @@ -0,0 +1,87 @@ +# A "migration" is, in technical terms, a plugin whose configuration describes +# how to read source data, process it (generally by mapping source fields to +# destination fields), and write it to Drupal. + +# The machine name for a migration, used to uniquely identify it. +id: beer_term + +# A human-friendly description of the migration. +label: Migrate style categories from the source database to taxonomy terms + +# The machine name of the group containing this migration (which contains shared +# configuration to be merged with our own configuration here). +migration_group: beer + +# Every migration must have a source plugin, which controls the delivery of our +# source data. In this case, our source plugin has the name "beer_term", which +# Drupal resolves to the PHP class defined in +# src/Plugin/migrate/source/BeerTerm.php. +source: + plugin: beer_term + +# Every migration must also have a destination plugin, which handles writing +# the migrated data in the appropriate form for that particular kind of data. +# Most Drupal content is an "entity" of one type or another, and we need to +# specify what entity type we are populating (in this case, taxonomy terms). +# Unlike the source plugin (which is specific to our particular scenario), this +# destination plugin is implemented in Drupal itself. +destination: + plugin: entity:taxonomy_term + +# Here's the meat of the migration - the processing pipeline. This describes how +# each destination field is to be populated based on the source data. For each +# destination field, one or more process plugins may be invoked. +process: + # The simplest process plugin is named 'get' - it is the default plugin, so + # does not need to be explicitly named. It simply copies the source value + # (the 'style' field from the source database in this case) to the destination + # field (the taxonomy term 'name' field). You can see we simply copy the + # source 'details' field to destination 'description' field in the same way. + name: style + description: details + + # Here is a new plugin - default_value. In its simplest usage here, it is used + # to hard-code a destination value, the vid (vocabulary ID) our taxonomy terms + # should be assigned to. It's important to note that while above the right + # side of the mappings was a source field name, here the right side of the + # 'default_value:' line is an actual value. + vid: + plugin: default_value + default_value: migrate_example_beer_styles + + # Here's another new plugin - migration. When importing data from another + # system, typically the unique identifiers for items on the destination side + # are not the same as the identifiers were on the source side. For example, in + # our style data the term names are the unique identifiers for each term, + # while in Drupal each term is assigned a unique integer term ID (tid). When + # any such items are referenced in Drupal, the reference needs to be + # translated from the old ID ('ale') to the new ID (1). The migration + # framework keeps track of the relationships between source and destination + # IDs in map tables, and the migration plugin is the means of performing a + # lookup in those map tables during processing. + parent: + plugin: migration + # Here we reference the migration whose map table we're performing a lookup + # against. You'll note that in this case we're actually referencing this + # migration itself, since category parents are imported by the same + # migration. This works best when we're sure the parents are imported + # before the children, and in this case our source plugin is guaranteeing + # that. + migration: beer_term + # 'style_parent' is the parent reference field from the source data. The + # result of this plugin is that the destination 'parent' field is populated + # with the Drupal term ID of the referenced style (or NULL if style_parent + # was empty). + source: style_parent + +# We'll learn more about dependencies in beer_node - here, we leave them empty. +migration_dependencies: {} + +# By default, configuration entities (like this migration) are not automatically +# removed when the migration which installed them is uninstalled. To have your +# migrations uninstalled with your migration module, add an enforced dependency +# on your module. +dependencies: + enforced: + module: + - migrate_example diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_user.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_user.yml new file mode 100644 index 000000000..66b08682b --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration.beer_user.yml @@ -0,0 +1,105 @@ +# Migration configuration for user accounts. We've described most of what goes +# into migration configuration in migrate_plus.migration.beer_term.yml, so won't +# repeat that here. +id: beer_user +label: Beer Drinkers of the world +migration_group: beer +source: + plugin: beer_user +destination: + plugin: entity:user +process: + pass: password + mail: email + init: email + status: status + roles: + plugin: default_value + default_value: 2 + + # Here's a new process plugin - dedupe_entity. Our source site allowed there + # to be multiple user accounts with the same username, but Drupal wants + # usernames to be unique. This plugin allows us to automatically generate + # unique usernames when we detect collisions. + name: + plugin: dedupe_entity + # The name of the source field containing the username. + source: username + # These next two settings identify the destination-side field to check for + # duplicates. They say "see if the incoming 'name' matches any existing + # 'name' field in any 'user' entity". + entity_type: user + field: name + # Finally, this specifies a string to use between the original value and the + # sequence number appended to make the value unique. Thus, the first 'alice' + # account gets the name 'alice' in Drupal, and the second one gets the name + # 'alice_1'. + postfix: _ + + # Another new process plugin - callback. This allows us to filter an incoming + # source value through an arbitrary PHP function. The function called must + # have one required argument. + created: + plugin: callback + # The 'registered' timestamp in the source data is a string of the form + # 'yyyy-mm-dd hh:mm:ss', but Drupal wants a UNIX timestamp for 'created'. + source: registered + callable: strtotime + + # Our source data only has a single timestamp value, 'registered', which we + # want to use for all four of Drupal's user timestamp fields. We could + # duplicate the callback plugin we used for 'created' above - but we have a + # shortcut. Putting an @ sign at the beginning of the source value indicates + # that it is to be interpreted as a *destination* field name instead of a + # *source* field name. Thus, if a value we need in more than one place + # requires some processing beyond simply copying it directly, we can perform + # that processing a single time and use the result in multiple places. + changed: '@created' + access: '@created' + login: '@created' + + # Yet another new process plugin - static_map. We're making a transformation + # in how we represent gender data - formerly it was integer values 0 for male + # and 1 for female, but in our modern Drupal site we will be making this a + # free-form text field, so we want to replace the obscure integers with + # simple strings. + field_migrate_example_gender: + plugin: static_map + # Specify the source field we're reading (containing 0's and 1's). + source: sex + # Tell it to transform 0 to 'Male', and 1 to 'Female'. + map: + 0: Male + 1: Female + # If the input is missing, leave the field empty. Without this, an empty + # or invalid source value would cause the user record to be skipped + # entirely. + bypass: true + + # This looks like a simple migration process plugin, but there's magic + # happening here. We import nodes after terms and users, because they have + # references to terms and users, so of course the terms and users must be + # migrated first - right? However, the favbeers field is a reference to the + # beer nodes which haven't yet been migrated - we have a circular relationship + # between users and nodes. The way the migration system resolves this + # situation is by creating "stubs". In this case, because no beer nodes have + # been created, each time a beer is looked up against the beer_node migration + # nothing is found, and by default the migration process plugin creates an + # empty stub node as a placeholder so the favbeers reference field has + # something to point to. The stub is recorded in the beer_node map table, so + # when that migration runs it knows that each incoming beer should overwrite + # its stub instead of creating a new node. + field_migrate_example_favbeers: + plugin: migration + source: beers + migration: beer_node + +migration_dependencies: {} + +# When a module is creating a custom content type it needs to add an +# enforced dependency to itself, otherwise the content type will persist +# after the module is disabled. See: https://www.drupal.org/node/2629516. +dependencies: + enforced: + module: + - migrate_example diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration_group.beer.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration_group.beer.yml new file mode 100644 index 000000000..7d802d3a9 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/config/install/migrate_plus.migration_group.beer.yml @@ -0,0 +1,38 @@ +# A "migration group" is - surprise! - a group of migrations. It is used to +# group migrations for display by our tools, and to perform operations on a +# specific set of migrations. It can also be used to hold any configuration +# common to those migrations, so it doesn't have to be duplicated in each one. + +# The machine name of the group, by which it is referenced in individual +# migrations. +id: beer + +# A human-friendly label for the group. +label: Beer Imports + +# More information about the group. +description: A few simple beer-related imports, to demonstrate how to implement migrations. + +# Short description of the type of source, e.g. "Drupal 6" or "WordPress". +source_type: Custom tables + +# Here we add any default configuration settings to be shared among all +# migrations in the group. For this example, the source tables are in the +# Drupal (default) database, but usually if your source data is in a +# database it will be external. +shared_configuration: + # Specifying 'source' here means that this configuration will be merged into + # the 'source' configuration of each migration. + source: + # A better practice for real-world migrations would be to add a database + # connection to your external database in settings.php and reference its + # key here. + key: default + +# As with the migration configuration (see beer_term), we add an enforced +# dependency so the migration_group configuration will be removed on module +# uninstall. +dependencies: + enforced: + module: + - migrate_example diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example.info.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example.info.yml new file mode 100644 index 000000000..678daccfd --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example.info.yml @@ -0,0 +1,15 @@ +type: module +name: Migrate Example +description: 'Examples of how Drupal 8 migration compares to previous versions.' +package: Examples +# core: 8.x +dependencies: + - drupal:migrate + - migrate_plus:migrate_example_setup + - migrate_plus:migrate_plus + +# Information added by Drupal.org packaging script on 2017-05-10 +version: '8.x-4.0-beta1' +core: '8.x' +project: 'migrate_plus' +datestamp: 1494450189 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/comment.type.node_comments.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/comment.type.node_comments.yml new file mode 100644 index 000000000..07629a81a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/comment.type.node_comments.yml @@ -0,0 +1,7 @@ +langcode: en +status: true +dependencies: { } +id: node_comments +label: 'Node comments' +target_entity_type_id: node +description: '' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.comment.node_comments.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.comment.node_comments.default.yml new file mode 100644 index 000000000..fc6a78e41 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.comment.node_comments.default.yml @@ -0,0 +1,30 @@ +langcode: en +status: true +dependencies: + config: + - comment.type.node_comments + - field.field.comment.node_comments.comment_body + module: + - text +id: comment.node_comments.default +targetEntityType: comment +bundle: node_comments +mode: default +content: + author: + weight: -2 + comment_body: + type: text_textarea + weight: 11 + settings: + rows: 5 + placeholder: '' + third_party_settings: { } + subject: + type: string_textfield + weight: 10 + settings: + size: 60 + placeholder: '' + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.node.migrate_example_beer.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.node.migrate_example_beer.default.yml new file mode 100644 index 000000000..306af0e3f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_form_display.node.migrate_example_beer.default.yml @@ -0,0 +1,87 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.migrate_example_beer.body + - field.field.node.migrate_example_beer.field_comments + - field.field.node.migrate_example_beer.field_migrate_example_beer_style + - field.field.node.migrate_example_beer.field_migrate_example_country + - field.field.node.migrate_example_beer.field_migrate_example_image + - node.type.migrate_example_beer + module: + - comment + - image + - text +id: node.migrate_example_beer.default +targetEntityType: node +bundle: migrate_example_beer +mode: default +content: + body: + type: text_textarea_with_summary + weight: 6 + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + third_party_settings: { } + created: + type: datetime_timestamp + weight: 2 + settings: { } + third_party_settings: { } + field_comments: + weight: 10 + settings: { } + third_party_settings: { } + type: comment_default + field_migrate_example_beer_style: + weight: 7 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + type: entity_reference_autocomplete + field_migrate_example_country: + weight: 8 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + type: string_textfield + field_migrate_example_image: + weight: 9 + settings: + progress_indicator: throbber + preview_image_style: thumbnail + third_party_settings: { } + type: image_image + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 3 + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 4 + third_party_settings: { } + title: + type: string_textfield + weight: 0 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 1 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.comment.node_comments.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.comment.node_comments.default.yml new file mode 100644 index 000000000..38e2b4339 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.comment.node_comments.default.yml @@ -0,0 +1,22 @@ +langcode: en +status: true +dependencies: + config: + - comment.type.node_comments + - field.field.comment.node_comments.comment_body + module: + - text +id: comment.node_comments.default +targetEntityType: comment +bundle: node_comments +mode: default +content: + comment_body: + label: hidden + type: text_default + weight: 0 + settings: { } + third_party_settings: { } + links: + weight: 100 +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.default.yml new file mode 100644 index 000000000..3a751080d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.default.yml @@ -0,0 +1,60 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.migrate_example_beer.body + - field.field.node.migrate_example_beer.field_comments + - field.field.node.migrate_example_beer.field_migrate_example_beer_style + - field.field.node.migrate_example_beer.field_migrate_example_country + - field.field.node.migrate_example_beer.field_migrate_example_image + - node.type.migrate_example_beer + module: + - comment + - image + - text + - user +id: node.migrate_example_beer.default +targetEntityType: node +bundle: migrate_example_beer +mode: default +content: + body: + label: hidden + type: text_default + weight: 2 + settings: { } + third_party_settings: { } + field_comments: + weight: 5 + label: above + settings: + pager_id: 0 + third_party_settings: { } + type: comment_default + field_migrate_example_beer_style: + weight: 3 + label: above + settings: + link: true + third_party_settings: { } + type: entity_reference_label + field_migrate_example_country: + weight: 4 + label: above + settings: + link_to_entity: false + third_party_settings: { } + type: string + field_migrate_example_image: + weight: 1 + label: above + settings: + image_style: '' + image_link: '' + third_party_settings: { } + type: image + links: + weight: 0 + settings: { } + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.teaser.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.teaser.yml new file mode 100644 index 000000000..dfc388bd2 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/core.entity_view_display.node.migrate_example_beer.teaser.yml @@ -0,0 +1,35 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.migrate_example_beer.body + - field.field.node.migrate_example_beer.field_comments + - field.field.node.migrate_example_beer.field_migrate_example_beer_style + - field.field.node.migrate_example_beer.field_migrate_example_country + - field.field.node.migrate_example_beer.field_migrate_example_image + - node.type.migrate_example_beer + module: + - text + - user +id: node.migrate_example_beer.teaser +targetEntityType: node +bundle: migrate_example_beer +mode: teaser +content: + body: + label: hidden + type: text_summary_or_trimmed + weight: 1 + settings: + trim_length: 600 + third_party_settings: { } + links: + weight: 0 + settings: { } + third_party_settings: { } +hidden: + field_comments: true + field_migrate_example_beer_style: true + field_migrate_example_country: true + field_migrate_example_image: true diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.comment.node_comments.comment_body.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.comment.node_comments.comment_body.yml new file mode 100644 index 000000000..844c7965a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.comment.node_comments.comment_body.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + config: + - comment.type.node_comments + - field.storage.comment.comment_body + module: + - text +id: comment.node_comments.comment_body +field_name: comment_body +entity_type: comment +bundle: node_comments +label: Comment +description: '' +required: true +translatable: true +default_value: { } +default_value_callback: '' +settings: { } +field_type: text_long diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.body.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.body.yml new file mode 100644 index 000000000..6e54441f0 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.body.yml @@ -0,0 +1,21 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.migrate_example_beer + module: + - text +id: node.migrate_example_beer.body +field_name: body +entity_type: node +bundle: migrate_example_beer +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true +field_type: text_with_summary diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_comments.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_comments.yml new file mode 100644 index 000000000..04a9900a1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_comments.yml @@ -0,0 +1,32 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_comments + - node.type.migrate_example_beer + module: + - comment +id: node.migrate_example_beer.field_comments +field_name: field_comments +entity_type: node +bundle: migrate_example_beer +label: Comments +description: '' +required: false +translatable: false +default_value: + - + status: 2 + cid: 0 + last_comment_timestamp: 0 + last_comment_name: null + last_comment_uid: 0 + comment_count: 0 +default_value_callback: '' +settings: + default_mode: 1 + per_page: 50 + anonymous: 0 + form_location: true + preview: 1 +field_type: comment diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_beer_style.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_beer_style.yml new file mode 100644 index 000000000..a5cb27ae6 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_beer_style.yml @@ -0,0 +1,26 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_beer_style + - node.type.migrate_example_beer + - taxonomy.vocabulary.migrate_example_beer_styles +id: node.migrate_example_beer.field_migrate_example_beer_style +field_name: field_migrate_example_beer_style +entity_type: node +bundle: migrate_example_beer +label: 'Migrate Example Beer Styles' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + migrate_example_beer_styles: migrate_example_beer_styles + sort: + field: _none + auto_create: false +field_type: entity_reference diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_country.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_country.yml new file mode 100644 index 000000000..4a0a525a7 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_country.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_country + - node.type.migrate_example_beer +id: node.migrate_example_beer.field_migrate_example_country +field_name: field_migrate_example_country +entity_type: node +bundle: migrate_example_beer +label: Countries +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_image.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_image.yml new file mode 100644 index 000000000..5337e4e96 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.node.migrate_example_beer.field_migrate_example_image.yml @@ -0,0 +1,37 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_image + - node.type.migrate_example_beer + module: + - image +id: node.migrate_example_beer.field_migrate_example_image +field_name: field_migrate_example_image +entity_type: node +bundle: migrate_example_beer +label: Image +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + file_directory: '' + file_extensions: 'png gif jpg jpeg' + max_filesize: '' + max_resolution: '' + min_resolution: '' + alt_field: true + alt_field_required: false + title_field: false + title_field_required: false + default_image: + uuid: '' + alt: '' + title: '' + width: null + height: null + handler: 'default:file' + handler_settings: { } +field_type: image diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_favbeers.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_favbeers.yml new file mode 100644 index 000000000..b85f3b62f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_favbeers.yml @@ -0,0 +1,27 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.user.field_migrate_example_favbeers + - node.type.migrate_example_beer + module: + - user +id: user.user.field_migrate_example_favbeers +field_name: field_migrate_example_favbeers +entity_type: user +bundle: user +label: 'Favorite Beers' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:node' + handler_settings: + target_bundles: + migrate_example_beer: migrate_example_beer + sort: + field: title + direction: ASC +field_type: entity_reference diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_gender.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_gender.yml new file mode 100644 index 000000000..c3dff123d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.field.user.user.field_migrate_example_gender.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.user.field_migrate_example_gender + module: + - user +id: user.user.field_migrate_example_gender +field_name: field_migrate_example_gender +entity_type: user +bundle: user +label: Gender +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_comments.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_comments.yml new file mode 100644 index 000000000..fd01476fe --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_comments.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - comment + - node +id: node.field_comments +field_name: field_comments +entity_type: node +type: comment +settings: + comment_type: node_comments +module: comment +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_beer_style.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_beer_style.yml new file mode 100644 index 000000000..9a037d7d6 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_beer_style.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_migrate_example_beer_style +field_name: field_migrate_example_beer_style +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_country.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_country.yml new file mode 100644 index 000000000..7f2ca7603 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_country.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + module: + - node +id: node.field_migrate_example_country +field_name: field_migrate_example_country +entity_type: node +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_image.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_image.yml new file mode 100644 index 000000000..db02f1626 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.node.field_migrate_example_image.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + module: + - file + - image + - node +id: node.field_migrate_example_image +field_name: field_migrate_example_image +entity_type: node +type: image +settings: + uri_scheme: public + default_image: + uuid: '' + alt: '' + title: '' + width: null + height: null + target_type: file + display_field: false + display_default: false +module: image +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_favbeers.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_favbeers.yml new file mode 100644 index 000000000..54bbe12c5 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_favbeers.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node + - user +id: user.field_migrate_example_favbeers +field_name: field_migrate_example_favbeers +entity_type: user +type: entity_reference +settings: + target_type: node +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_gender.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_gender.yml new file mode 100644 index 000000000..34fcc9032 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/field.storage.user.field_migrate_example_gender.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + module: + - user +id: user.field_migrate_example_gender +field_name: field_migrate_example_gender +entity_type: user +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/node.type.migrate_example_beer.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/node.type.migrate_example_beer.yml new file mode 100644 index 000000000..24c2e1da5 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/node.type.migrate_example_beer.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +name: Beer +type: migrate_example_beer +description: 'Beer is what we drink.' +help: '' +new_revision: false +preview_mode: 1 +display_submitted: true diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/taxonomy.vocabulary.migrate_example_beer_styles.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/taxonomy.vocabulary.migrate_example_beer_styles.yml new file mode 100644 index 000000000..afad4b0dd --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/config/install/taxonomy.vocabulary.migrate_example_beer_styles.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +name: 'Migrate Example Beer Styles' +vid: migrate_example_beer_styles +description: 'Use tags to group beers on similar topics into categories.' +hierarchy: 0 +weight: 0 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.info.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.info.yml new file mode 100644 index 000000000..814be16de --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.info.yml @@ -0,0 +1,18 @@ +type: module +name: Migrate Example Setup +description: 'Separate site configuration for the example from the actual migration.' +package: Migration +# core: 8.x +hidden: 1 +dependencies: + - drupal:comment + - drupal:image + - drupal:text + - drupal:options + - drupal:taxonomy + +# Information added by Drupal.org packaging script on 2017-05-10 +version: '8.x-4.0-beta1' +core: '8.x' +project: 'migrate_plus' +datestamp: 1494450189 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.install b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.install new file mode 100644 index 000000000..a8bda3088 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrate_example_setup/migrate_example_setup.install @@ -0,0 +1,345 @@ + 'Beers of the world.', + 'fields' => array( + 'bid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Beer ID.', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'body' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Full description of the beer.', + ), + 'excerpt' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Abstract for this beer.', + ), + 'countries' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Countries of origin. Multiple values, delimited by pipe', + ), + 'aid' => array( + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'Account Id of the author.', + ), + 'image' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Image path', + ), + 'image_alt' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Image ALT', + ), + 'image_title' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Image title', + ), + 'image_description' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Image description', + ), + ), + 'primary key' => array('bid'), + ); +} + +function migrate_example_beer_schema_topic() { + return array( + 'description' => 'Categories', + 'fields' => array( + 'style' => array( + 'type' => 'varchar_ascii', + 'length' => 255, + 'not null' => TRUE, + ), + 'details' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + ), + 'style_parent' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Parent topic, if any', + ), + 'region' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Region first associated with this style', + ), + 'hoppiness' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Relative hoppiness of the beer', + ), + ), + 'primary key' => array('style'), + ); +} + +function migrate_example_beer_schema_topic_node() { + return array( + 'description' => 'Beers topic pairs.', + 'fields' => array( + 'bid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Beer ID.', + ), + 'style' => array( + 'type' => 'varchar_ascii', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Topic name', + ), + ), + 'primary key' => array('style', 'bid'), + ); +} + +function migrate_example_beer_schema_comment() { + return array( + 'description' => 'Beers comments.', + 'fields' => array( + 'cid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Comment ID.', + ), + 'bid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Beer ID that is being commented upon', + ), + 'cid_parent' => array( + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'Parent comment ID in case of comment replies.', + ), + 'subject' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment subject', + ), + 'body' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment body', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment name (if anon)', + ), + 'mail' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment email (if anon)', + ), + 'aid' => array( + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'Account ID (if any).', + ), + ), + 'primary key' => array('cid'), + ); +} + +function migrate_example_beer_schema_account() { + return array( + 'description' => 'Beers accounts.', + 'fields' => array( + 'aid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Account ID', + ), + 'status' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Blocked_Allowed', + ), + 'registered' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Registration date', + ), + 'username' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account name (for login)', + ), + 'nickname' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account name (for display)', + ), + 'password' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account password (raw)', + ), + 'email' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account email', + ), + 'sex' => array( + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'Gender (0 for male, 1 for female)', + ), + 'beers' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Favorite Beers', + ), + ), + 'primary key' => array('aid'), + ); +} + +function migrate_example_beer_data_node() { + $fields = array('bid', 'name', 'body', 'excerpt', 'countries', 'aid', 'image', + 'image_alt', 'image_title', 'image_description'); + $query = db_insert('migrate_example_beer_node') + ->fields($fields); + // Use high bid numbers to avoid overwriting an existing node id. + $data = array( + array(99999999, 'Heineken', 'Blab Blah Blah Green', 'Green', 'Netherlands|Belgium', 0, 'heineken.jpg', 'Heinekin alt', 'Heinekin title', 'Heinekin description'), // comes with migrate_example project. + array(99999998, 'Miller Lite', 'We love Miller Brewing', 'Tasteless', 'USA|Canada', 1, NULL, NULL, NULL, NULL), + array(99999997, 'Boddington', 'English occasionally get something right', 'A treat', 'United Kingdom', 1, NULL, NULL, NULL, NULL), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +// Note that alice has duplicate username. Exercises dedupe_entity plugin. +// @TODO duplicate email also. +function migrate_example_beer_data_account() { + $fields = array('status', 'registered', 'username', 'nickname', 'password', 'email', 'sex', 'beers'); + $query = db_insert('migrate_example_beer_account') + ->fields($fields); + $data = array( + array(1, '2010-03-30 10:31:05', 'alice', 'alice in beerland', 'alicepass', 'alice@example.com', '1', '99999999|99999998|99999997'), + array(1, '2010-04-04 10:31:05', 'alice', 'alice in aleland', 'alicepass', 'alice2@example.com', '1', '99999999|99999998|99999997'), + array(0, '2007-03-15 10:31:05', 'bob', 'rebob', 'bobpass', 'bob@example.com', '0', '99999999|99999997'), + array(1, '2004-02-29 10:31:05', 'charlie', 'charlie chocolate', 'mykids', 'charlie@example.com', '0', '99999999|99999998'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_beer_data_comment() { + $fields = array('bid', 'cid_parent', 'subject', 'body', 'name', 'mail', 'aid'); + $query = db_insert('migrate_example_beer_comment') + ->fields($fields); + $data = array( + array(99999998, NULL, 'im first', 'full body', 'alice', 'alice@example.com', 0), + array(99999998, NULL, 'im second', 'aromatic', 'alice', 'alice@example.com', 0), + array(99999999, NULL, 'im parent', 'malty', 'alice', 'alice@example.com', 0), + array(99999999, 1, 'im child', 'cold body', 'bob', NULL, 1), + array(99999999, 4, 'im grandchild', 'bitter body', 'charlie@example.com', NULL, 1), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_beer_data_topic() { + $fields = array('style', 'details', 'style_parent', 'region', 'hoppiness'); + $query = db_insert('migrate_example_beer_topic') + ->fields($fields); + $data = array( + array('ale', 'traditional', NULL, 'Medieval British Isles', 'Medium'), + array('red ale', 'colorful', 'ale', NULL, NULL), + array('pilsner', 'refreshing', NULL, 'Pilsen, Bohemia (now Czech Republic)', 'Low'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_beer_data_topic_node() { + $fields = array('bid', 'style'); + $query = db_insert('migrate_example_beer_topic_node') + ->fields($fields); + $data = array( + array(99999999, 'pilsner'), + array(99999999, 'red ale'), + array(99999998, 'red ale'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrations/beer_comment.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrations/beer_comment.yml new file mode 100644 index 000000000..e631e9ac8 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/migrations/beer_comment.yml @@ -0,0 +1,45 @@ +# Migration configuration for beer comments. No new concepts here. +id: beer_comment +label: Comments on beers +migration_group: beer +source: + plugin: beer_comment +destination: + plugin: entity:comment +process: + pid: + plugin: migration + migration: beer_comment + source: cid_parent + entity_id: + plugin: migration + migration: beer_node + source: bid + entity_type: + plugin: default_value + default_value: node + field_name: + plugin: default_value + default_value: field_comments + comment_type: + plugin: default_value + default_value: node_comments + subject: subject + uid: + plugin: migration + migration: beer_user + source: aid + name: name + mail: mail + status: + plugin: default_value + default_value: 1 + 'comment_body/value': body +migration_dependencies: + required: + - beer_node + - beer_user +dependencies: + enforced: + module: + - migrate_example diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerComment.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerComment.php new file mode 100644 index 000000000..217fad262 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerComment.php @@ -0,0 +1,56 @@ +select('migrate_example_beer_comment', 'mec') + ->fields('mec', ['cid', 'cid_parent', 'name', 'mail', 'aid', + 'body', 'bid', 'subject']) + ->orderBy('cid_parent', 'ASC'); + return $query; + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'cid' => $this->t('Comment ID'), + 'cid_parent' => $this->t('Parent comment ID in case of comment replies'), + 'name' => $this->t('Comment name (if anon)'), + 'mail' => $this->t('Comment email (if anon)'), + 'aid' => $this->t('Account ID (if any)'), + 'bid' => $this->t('Beer ID that is being commented upon'), + 'subject' => $this->t('Comment subject'), + ]; + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + return [ + 'cid' => [ + 'type' => 'integer', + 'alias' => 'mec', + ], + ]; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerNode.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerNode.php new file mode 100644 index 000000000..8d9f0bbfd --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerNode.php @@ -0,0 +1,99 @@ +select('migrate_example_beer_node', 'b') + ->fields('b', ['bid', 'name', 'body', 'excerpt', 'aid', + 'countries', 'image', 'image_alt', 'image_title', + 'image_description']); + return $query; + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'bid' => $this->t('Beer ID'), + 'name' => $this->t('Name of beer'), + 'body' => $this->t('Full description of the beer'), + 'excerpt' => $this->t('Abstract for this beer'), + 'aid' => $this->t('Account ID of the author'), + 'countries' => $this->t('Countries of origin. Multiple values, delimited by pipe'), + 'image' => $this->t('Image path'), + 'image_alt' => $this->t('Image ALT'), + 'image_title' => $this->t('Image title'), + 'image_description' => $this->t('Image description'), + // Note that this field is not part of the query above - it is populated + // by prepareRow() below. You should document all source properties that + // are available for mapping after prepareRow() is called. + 'terms' => $this->t('Applicable styles'), + ]; + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + return [ + 'bid' => [ + 'type' => 'integer', + 'alias' => 'b', + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function prepareRow(Row $row) { + /** + * As explained above, we need to pull the style relationships into our + * source row here, as an array of 'style' values (the unique ID for + * the beer_term migration). + */ + $terms = $this->select('migrate_example_beer_topic_node', 'bt') + ->fields('bt', ['style']) + ->condition('bid', $row->getSourceProperty('bid')) + ->execute() + ->fetchCol(); + $row->setSourceProperty('terms', $terms); + + // As we did for favorite beers in the user migration, we need to explode + // the multi-value country names. + if ($value = $row->getSourceProperty('countries')) { + $row->setSourceProperty('countries', explode('|', $value)); + } + return parent::prepareRow($row); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerTerm.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerTerm.php new file mode 100644 index 000000000..f8ea51efe --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerTerm.php @@ -0,0 +1,88 @@ +select() call - this ensures + * that the query is executed against the database configured for this + * source plugin. + */ + return $this->select('migrate_example_beer_topic', 'met') + ->fields('met', ['style', 'details', 'style_parent', 'region', 'hoppiness']) + // We sort this way to ensure parent terms are imported first. + ->orderBy('style_parent', 'ASC'); + } + + /** + * {@inheritdoc} + */ + public function fields() { + /** + * This method simply documents the available source fields provided by + * the source plugin, for use by front-end tools. It returns an array keyed + * by field/column name, with the value being a translated string explaining + * to humans what the field represents. You should always + */ + $fields = [ + 'style' => $this->t('Account ID'), + 'details' => $this->t('Blocked/Allowed'), + 'style_parent' => $this->t('Registered date'), + // These values are not currently migrated - it's OK to skip fields you + // don't need. + 'region' => $this->t('Region the style is associated with'), + 'hoppiness' => $this->t('Hoppiness of the style'), + ]; + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + /** + * This method indicates what field(s) from the source row uniquely identify + * that source row, and what their types are. This is critical information + * for managing the migration. The keys of the returned array are the field + * names from the query which comprise the unique identifier. The values are + * arrays indicating the type of the field, used for creating compatible + * columns in the map tables that track processed items. + */ + return [ + 'style' => [ + 'type' => 'string', + // 'alias' is the alias for the table containing 'style' in the query + // defined above. Optional in this case, but necessary if the same + // column may occur in multiple tables in a join. + 'alias' => 'met', + ], + ]; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerUser.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerUser.php new file mode 100644 index 000000000..b0d963d3f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example/src/Plugin/migrate/source/BeerUser.php @@ -0,0 +1,85 @@ +select('migrate_example_beer_account', 'mea') + ->fields('mea', ['aid', 'status', 'registered', 'username', 'nickname', + 'password', 'email', 'sex', 'beers']); + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'aid' => $this->t('Account ID'), + 'status' => $this->t('Blocked/Allowed'), + 'registered' => $this->t('Registered date'), + 'username' => $this->t('Account name (for login)'), + 'nickname' => $this->t('Account name (for display)'), + 'password' => $this->t('Account password (raw)'), + 'email' => $this->t('Account email'), + 'sex' => $this->t('Gender'), + 'beers' => $this->t('Favorite beers, pipe-separated'), + ]; + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + return [ + 'aid' => [ + 'type' => 'integer', + 'alias' => 'mea', + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function prepareRow(Row $row) { + /** + * prepareRow() is the most common place to perform custom run-time + * processing that isn't handled by an existing process plugin. It is called + * when the raw data has been pulled from the source, and provides the + * opportunity to modify or add to that data, creating the canonical set of + * source data that will be fed into the processing pipeline. + * + * In our particular case, the list of a user's favorite beers is a pipe- + * separated list of beer IDs. The processing pipeline deals with arrays + * representing multi-value fields naturally, so we want to explode that + * string to an array of individual beer IDs. + */ + if ($value = $row->getSourceProperty('beers')) { + $row->setSourceProperty('beers', explode('|', $value)); + } + /** + * Always call your parent! Essential processing is performed in the base + * class. Be mindful that prepareRow() returns a boolean status - if FALSE + * that indicates that the item being processed should be skipped. Unless + * we're deciding to skip an item ourselves, let the parent class decide. + */ + return parent::prepareRow($row); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/README.txt b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/README.txt new file mode 100644 index 000000000..8d5a25d80 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/README.txt @@ -0,0 +1,58 @@ +INTRODUCTION +------------ +The migrate_example_advanced module demonstrates some techniques for Drupal 8 +migrations beyond the basics in migrate_example. It includes a group of +migrations with a wine theme. + +SETUP +----- +To demonstrate XML migrations as realistically as possible, the setup module +provides the source data as REST services. So the migrations' references to these +services can be set up accurately, if you install migrate_example_advanced via +drush be sure to use the --uri parameter, e.g. + +drush en -y migrate_example_advanced --uri=http://d8.local:8083/ + +THE WINE SITE +------------- +In this scenario, we have a wine aficionado site which stores data in SQL tables +as well is pulling in additional data from XML services. + +To make the example as simple as to run as possible, the SQL data is placed in +tables directly in your Drupal database - in most real-world scenarios, your +source data will be in an external database. The migrate_example_advanced_setup +submodule creates and populates these tables, as well as configuring your Drupal +8 site (creating node types, vocabularies, fields, etc.) to receive the data, +and providing service endpoints for XML data. + +STRUCTURE +--------- +As with most custom migrations, there are two primary components to this +example: + +1. Migration configuration, in the config/install directory. These YAML files + describe the migration process and provide the mappings from the source data + to Drupal's destination entities. + +2. Source plugins, in src/Plugin/migrate/source. These are referenced from the + configuration files, and provide the source data to the migration processing + pipeline, as well as manipulating that data where necessary to put it into + a canonical form for migrations. + +UNDERSTANDING THE MIGRATIONS +---------------------------- +Basic techniques demonstrated in the migrate_example module are not rehashed +here - it is expected that if you are learning Drupal 8 migration, you will +study and understand those examples first, and use migrate_example_advanced to +learn about specific techniques beyond those basics. This example doesn't have +the narrative form of migrate_example - it's more of a grab-bag demonstrating +varous features, and is more of a reference for, say, copying the code to set +up an XML migration. An index of things demonstrated by this module: + +Multiple vocabularies populated in one migration +------------------------------------------------ +See migrate_plus.migration.wine_terms.yml. + +Importing from XML services +--------------------------- +See migrate_plus.migration.wine_role_xml.yml. diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml new file mode 100755 index 000000000..ae2ad03ab --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml @@ -0,0 +1,50 @@ +# This migration demonstrates importing from SOAP/WSDL. +id: weather_soap +label: SOAP service providing weather. +migration_group: wine +source: + # We use the SOAP parser source plugin. + plugin: url + data_fetcher_plugin: http # Ignored - SoapClient does the fetching. + data_parser_plugin: soap + # URL of a WSDL endpoint. + urls: http://www.webservicex.net/globalweather.asmx?WSDL + # The function to call on the service, and the parameters to pass. See + # http://www.webservicex.net/New/Home/ServiceDetail/56 for the XML structure + # of this feed - how CountryName is passed within the GetCitiesByCountry + # XML element. + function: GetCitiesByCountry + parameters: + CountryName: Spain + # Responses may be returned as an XML string, an object, or an array - specify + # the type of response here. + response_type: xml + # Looking at the XML response at http://www.webservicex.net/globalweather.asmx/GetCitiesByCountry, + # we see that the data items we want are within . + item_selector: /NewDataSet/Table + # For each field, 'name' is the source property name to be used in the process + # steps below, 'label' is optional (to document the property), and selector + # is an xpath (-like, for array and object returns) string relative to the + # item_selector for retrieving that data value. + fields: + - + name: Country + label: Country + selector: Country + - + name: City + label: City + selector: City + # 'ids' tells us what source property ('City') holds the unique identifying + # value for each imported item, and what schema type to use to hold that + # value in the migration map an message tables. + ids: + City: + type: string +process: + vid: + plugin: default_value + default_value: migrate_example_wine_varieties + name: City +destination: + plugin: entity:taxonomy_term diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_json.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_json.yml new file mode 100755 index 000000000..e8991a699 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_json.yml @@ -0,0 +1,55 @@ +# This migration demonstrates importing from a monolithic JSON file. +id: wine_role_json +label: JSON feed of roles (positions) +migration_group: wine +source: + # We use the JSON source plugin. + plugin: url + data_fetcher_plugin: http + data_parser_plugin: json + # The data_parser normally limits the fields passed on to the source plugin + # to fields configured to be used as part of the migration. To support more + # dynamic migrations, the JSON data parser supports including the original + # data for the current row. Simply include the 'include_raw_data' flag set + # to `true` to enable this. This option is disabled by default to minimize + # memory footprint for migrations that do not need this capability. + # include_raw_data: true + # Normally, this is one or more fully-qualified URLs or file paths. Because + # we can't hardcode your local URL, we provide a relative path here which + # hook_install() will rewrite to a full URL for the current site. + urls: /migrate_example_advanced_position?_format=json + # An xpath-like selector corresponding to the items to be imported. + item_selector: position + # Under 'fields', we list the data items to be imported. The first level keys + # are the source field names we want to populate (the names to be used as + # sources in the process configuration below). For each field we're importing, + # we provide a label (optional - this is for display in migration tools) and + # an xpath for retrieving that value. It's important to note that this xpath + # is relative to the elements retrieved by item_selector. + fields: + - + name: machine_name + label: 'Unique position identifier' + selector: sourceid + - + name: friendly_name + label: 'Position name' + selector: name + # Under 'ids', we identify source fields populated above which will uniquely + # identify each imported item. The 'type' makes sure the migration map table + # uses the proper schema type for stored the IDs. + ids: + machine_name: + type: string +process: + # Note that the source field names here (machine_name and friendly_name) were + # defined by the 'fields' configuration for the source plugin above. + id: machine_name + label: friendly_name +destination: + plugin: entity:user_role +migration_dependencies: {} +dependencies: + enforced: + module: + - migrate_example_advanced diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_xml.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_xml.yml new file mode 100755 index 000000000..6b7234c24 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_role_xml.yml @@ -0,0 +1,51 @@ +# This migration demonstrates importing from a monolithic XML file. +id: wine_role_xml +label: XML feed of roles (positions) +migration_group: wine +source: + # We use the XML data parser plugin. + plugin: url + data_fetcher_plugin: http + data_parser_plugin: xml + # Normally, this is one or more fully-qualified URLs or file paths. Because + # we can't hardcode your local URL, we provide a relative path here which + # hook_install() will rewrite to a full URL for the current site. + urls: /migrate_example_advanced_position?_format=xml + # Visit the URL above (relative to your site root) and look at it. You can see + # that is the outer element, and each item we want to import is a + # element. The item_xpath value is the xpath to use to query the + # desired elements. + item_selector: /response/position + # Under 'fields', we list the data items to be imported. The first level keys + # are the source field names we want to populate (the names to be used as + # sources in the process configuration below). For each field we're importing, + # we provide a label (optional - this is for display in migration tools) and + # an xpath for retrieving that value. It's important to note that this xpath + # is relative to the elements retrieved by item_xpath. + fields: + - + name: machine_name + label: 'Unique position identifier' + selector: sourceid + - + name: friendly_name + label: 'Position name' + selector: name + # Under 'ids', we identify source fields populated above which will uniquely + # identify each imported item. The 'type' makes sure the migration map table + # uses the proper schema type for stored the IDs. + ids: + machine_name: + type: string +process: + # Note that the source field names here (machine_name and friendly_name) were + # defined by the 'fields' configuration for the source plugin above. + id: machine_name + label: friendly_name +destination: + plugin: entity:user_role +migration_dependencies: {} +dependencies: + enforced: + module: + - migrate_example_advanced diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_terms.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_terms.yml new file mode 100644 index 000000000..f11b82f84 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_terms.yml @@ -0,0 +1,37 @@ +id: wine_terms +label: Migrate all categories into Drupal taxonomy terms +migration_group: wine +source: + plugin: wine_term +destination: + plugin: entity:taxonomy_term +process: + name: name + description: details + # Usually, one wants to have a separate migration for each entity_type/bundle + # combination - e.g., separate migrations for articles and blog posts, as + # opposed to a single monolithic node migration. This affords maximum + # control - the ability to import just one bundle at a time, and most + # importantly to have distinct field mappings (because different node types + # usually have different fields). In this case, though, because all of the + # vocabularies we're importing come from a common table, and on the Drupal + # side there are no distinct custom fields, we are able to import them all in + # one migration. The static_map tells the migration in which vocabulary to + # place each term, based on the incoming 'type' column. + vid: + plugin: static_map + source: type + map: + best_with: migrate_example_wine_best_with + region: migrate_example_wine_regions + variety: migrate_example_wine_varieties + parent: + plugin: migration + migration: wine_terms + source: category_parent + weight: ordering +migration_dependencies: {} +dependencies: + enforced: + module: + - migrate_example_advanced diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_list.yml.txt b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_list.yml.txt new file mode 100755 index 000000000..ae4d2b747 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_list.yml.txt @@ -0,0 +1,56 @@ +# This migration demonstrates importing from an endpoint listing other endpoints +# containing individual item data. +id: wine_variety_list +label: XML feed of varieties +migration_group: wine +source: + # We use the XML source plugin. + plugin: xml + # Normally, this is one or more fully-qualified URLs or file paths. Because + # we can't hardcode your local URL, we provide a relative path here which + # hook_install() will rewrite to a full URL for the current site. + urls: /migrate_example_advanced_variety_list?_format=xml + item_url: /migrate_example_advanced_variety_list/:id?_format=xml + id_selector: /response/items + # Visit the URL above (relative to your site root) and look at it. You can see + # that is the outer element, and each item we want to import is a + # element. The item_xpath value is the xpath to use to query the + # desired elements. + item_selector: /response/variety + # Under 'fields', we list the data items to be imported. The first level keys + # are the source field names we want to populate (the names to be used as + # sources in the process configuration below). For each field we're importing, + # we provide a label (optional - this is for display in migration tools) and + # an xpath for retrieving that value. It's important to note that this xpath + # is relative to the elements retrieved by item_xpath. + fields: + category_name: + label: + selector: name + category_details: + label: + selector: details + category_parent: + label: 'Unique position identifier' + selector: parent + # Under 'ids', we identify source fields populated above which will uniquely + # identify each imported item. The 'type' makes sure the migration map table + # uses the proper schema type for stored the IDs. + ids: + category_name: + type: string +process: + vid: + plugin: default_value + default_value: migrate_example_wine_varieties + name: category_name + description: category_details + parent: + plugin: migration + migration: wine_terms + source: category_parent +destination: + plugin: entity:taxonomy_term +migration_dependencies: + require: + - wine_terms diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_multi_xml.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_multi_xml.yml new file mode 100755 index 000000000..e26579e71 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration.wine_variety_multi_xml.yml @@ -0,0 +1,69 @@ +# This migration demonstrates importing from multiple XML files. +id: wine_variety_multi_xml +label: XML feed of varieties +migration_group: wine +source: + # We use the XML source plugin. + plugin: url + data_fetcher_plugin: http + data_parser_plugin: xml + # Normally, this is one or more fully-qualified URLs or file paths. Because + # we can't hardcode your local URL, we provide a relative path here which + # hook_install() will rewrite to a full URL for the current site. + urls: + - /migrate_example_advanced_variety_multiple/red?_format=xml + - /migrate_example_advanced_variety_multiple/white?_format=xml + # Visit the URL above (relative to your site root) and look at it. You can see + # that is the outer element, and each item we want to import is a + # element. The item_xpath value is the xpath to use to query the + # desired elements. + item_selector: /response/variety + # Under 'fields', we list the data items to be imported. The first level keys + # are the source field names we want to populate (the names to be used as + # sources in the process configuration below). For each field we're importing, + # we provide a label (optional - this is for display in migration tools) and + # an xpath for retrieving that value. It's important to note that this xpath + # is relative to the elements retrieved by item_xpath. + fields: + - + name: category_name + label: Name + selector: name + - + name: category_details + label: Details + selector: details + - + name: category_parent + label: 'Unique position identifier' + selector: parent + - + name: category_attributes + label: 'List of variety attributes' + selector: attributes + # Under 'ids', we identify source fields populated above which will uniquely + # identify each imported item. The 'type' makes sure the migration map table + # uses the proper schema type for stored the IDs. + ids: + category_name: + type: string +process: + vid: + plugin: default_value + default_value: migrate_example_wine_varieties + name: category_name + description: category_details + parent: + plugin: migration + migration: wine_terms + source: category_parent + field_variety_attributes: category_attributes +destination: + plugin: entity:taxonomy_term +migration_dependencies: + required: + - wine_terms +dependencies: + enforced: + module: + - migrate_example_advanced diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration_group.wine.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration_group.wine.yml new file mode 100644 index 000000000..5a14bf29b --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/config/install/migrate_plus.migration_group.wine.yml @@ -0,0 +1,11 @@ +id: wine +label: Wine Imports +description: A few wine-related imports, demonstrating some more advanced migration techniques. +source_type: Custom tables and XML +shared_configuration: + source: + key: default +dependencies: + enforced: + module: + - migrate_example_advanced diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0001.xml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0001.xml new file mode 100644 index 000000000..a78c02bf0 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0001.xml @@ -0,0 +1,7 @@ + + + Lolonis Winery + Makers of Ladybug Red + 3 + Redwood Valley + diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0002.xml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0002.xml new file mode 100644 index 000000000..380113b92 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/0002.xml @@ -0,0 +1,7 @@ + + + Château Latour + Makers of grand vin Chateau Latour, Les Forts de Latour and Pauillac + 3 + Bordeaux + diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index.xml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index.xml new file mode 100644 index 000000000..28053984e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index.xml @@ -0,0 +1,4 @@ + + + 0001 + diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index2.xml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index2.xml new file mode 100644 index 000000000..9dfa50022 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/data/index2.xml @@ -0,0 +1,4 @@ + + + 0002 + diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.info.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.info.yml new file mode 100644 index 000000000..ba5e45b74 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.info.yml @@ -0,0 +1,15 @@ +type: module +name: Migrate Example (Advanced) +description: 'Specialized examples of Drupal 8 migration.' +package: Examples +# core: 8.x +dependencies: + - drupal:migrate + - migrate_plus:migrate_example_advanced_setup + - migrate_plus:migrate_plus + +# Information added by Drupal.org packaging script on 2017-05-10 +version: '8.x-4.0-beta1' +core: '8.x' +project: 'migrate_plus' +datestamp: 1494450189 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.install b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.install new file mode 100644 index 000000000..b2506e4a9 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced.install @@ -0,0 +1,50 @@ +get('source'); + $request = \Drupal::request(); + $source['urls'] = 'http://' . $request->getHttpHost() . $source['urls']; + $wine_role_xml_migration->set('source', $source); + $wine_role_xml_migration->save(); + } + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $wine_role_json_migration */ + $wine_role_json_migration = Migration::load('wine_role_json'); + if ($wine_role_json_migration) { + $source = $wine_role_json_migration->get('source'); + $request = \Drupal::request(); + $source['urls'] = 'http://' . $request->getHttpHost() . $source['urls']; + $wine_role_json_migration->set('source', $source); + $wine_role_json_migration->save(); + } + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $wine_variety_multi_xml_migration */ + $wine_variety_multi_xml_migration = Migration::load('wine_variety_multi_xml'); + if ($wine_variety_multi_xml_migration) { + $source = $wine_variety_multi_xml_migration->get('source'); + $request = \Drupal::request(); + $urls = []; + foreach ($source['urls'] as $url) { + $urls[] = 'http://' . $request->getHttpHost() . $url; + } + $source['urls'] = $urls; + $wine_variety_multi_xml_migration->set('source', $source); + $wine_variety_multi_xml_migration->save(); + } +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/comment.type.migrate_example_advanced_comment.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/comment.type.migrate_example_advanced_comment.yml new file mode 100644 index 000000000..ba582793d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/comment.type.migrate_example_advanced_comment.yml @@ -0,0 +1,7 @@ +langcode: en +status: true +dependencies: { } +id: migrate_example_advanced_comment +label: 'Node comments' +target_entity_type_id: node +description: '' diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.comment.migrate_example_advanced_comment.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.comment.migrate_example_advanced_comment.default.yml new file mode 100644 index 000000000..518664e2b --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.comment.migrate_example_advanced_comment.default.yml @@ -0,0 +1,30 @@ +langcode: en +status: true +dependencies: + config: + - comment.type.migrate_example_advanced_comment + - field.field.comment.migrate_example_advanced_comment.comment_body + module: + - text +id: comment.migrate_example_advanced_comment.default +targetEntityType: comment +bundle: migrate_example_advanced_comment +mode: default +content: + author: + weight: -2 + comment_body: + type: text_textarea + weight: 11 + settings: + rows: 5 + placeholder: '' + third_party_settings: { } + subject: + type: string_textfield + weight: 10 + settings: + size: 60 + placeholder: '' + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_producer.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_producer.default.yml new file mode 100644 index 000000000..89df7690e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_producer.default.yml @@ -0,0 +1,69 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.migrate_example_producer.body + - field.field.node.migrate_example_producer.field_migrate_example_wine_regio + - node.type.migrate_example_producer + module: + - path + - text +id: node.migrate_example_producer.default +targetEntityType: node +bundle: migrate_example_producer +mode: default +content: + body: + type: text_textarea_with_summary + weight: 31 + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + third_party_settings: { } + created: + type: datetime_timestamp + weight: 10 + settings: { } + third_party_settings: { } + field_migrate_example_wine_regio: + weight: 32 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + type: entity_reference_autocomplete + path: + type: path + weight: 30 + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 15 + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 16 + third_party_settings: { } + title: + type: string_textfield + weight: -5 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_wine.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_wine.default.yml new file mode 100644 index 000000000..0ef5edb66 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.node.migrate_example_wine.default.yml @@ -0,0 +1,117 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.migrate_example_wine.body + - field.field.node.migrate_example_wine.field_migrate_example_comments + - field.field.node.migrate_example_wine.field_migrate_example_adv_image + - field.field.node.migrate_example_wine.field_migrate_example_top_vintag + - field.field.node.migrate_example_wine.field_migrate_example_wine_best + - field.field.node.migrate_example_wine.field_migrate_example_wine_ratin + - field.field.node.migrate_example_wine.field_migrate_example_wine_regio + - field.field.node.migrate_example_wine.field_migrate_example_wine_var + - node.type.migrate_example_wine + module: + - comment + - image + - path + - text +id: node.migrate_example_wine.default +targetEntityType: node +bundle: migrate_example_wine +mode: default +content: + body: + type: text_textarea_with_summary + weight: 31 + settings: + rows: 9 + summary_rows: 3 + placeholder: '' + third_party_settings: { } + created: + type: datetime_timestamp + weight: 10 + settings: { } + third_party_settings: { } + field_migrate_example_comments: + weight: 38 + settings: { } + third_party_settings: { } + type: comment_default + field_migrate_example_adv_image: + weight: 35 + settings: + progress_indicator: throbber + preview_image_style: thumbnail + third_party_settings: { } + type: image_image + field_migrate_example_top_vintag: + weight: 37 + settings: + placeholder: '' + third_party_settings: { } + type: number + field_migrate_example_wine_best: + weight: 34 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + type: entity_reference_autocomplete_tags + field_migrate_example_wine_ratin: + weight: 36 + settings: + placeholder: '' + third_party_settings: { } + type: number + field_migrate_example_wine_regio: + weight: 33 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + type: entity_reference_autocomplete + field_migrate_example_wine_var: + weight: 32 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + type: entity_reference_autocomplete + path: + type: path + weight: 30 + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 15 + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 16 + third_party_settings: { } + title: + type: string_textfield + weight: -5 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.taxonomy_term.migrate_example_wine_varieties.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.taxonomy_term.migrate_example_wine_varieties.default.yml new file mode 100644 index 000000000..32bd69244 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_form_display.taxonomy_term.migrate_example_wine_varieties.default.yml @@ -0,0 +1,41 @@ +langcode: en +status: true +dependencies: + config: + - field.field.taxonomy_term.migrate_example_wine_varieties.field_variety_attributes + - taxonomy.vocabulary.migrate_example_wine_varieties + module: + - path + - text +id: taxonomy_term.migrate_example_wine_varieties.default +targetEntityType: taxonomy_term +bundle: migrate_example_wine_varieties +mode: default +content: + description: + type: text_textarea + weight: 1 + settings: + placeholder: '' + rows: 5 + third_party_settings: { } + field_variety_attributes: + type: string_textfield + weight: 3 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + name: + type: string_textfield + weight: 0 + settings: + size: 60 + placeholder: '' + third_party_settings: { } + path: + type: path + weight: 2 + settings: { } + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.comment.migrate_example_advanced_comment.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.comment.migrate_example_advanced_comment.default.yml new file mode 100644 index 000000000..b4b97f7de --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.comment.migrate_example_advanced_comment.default.yml @@ -0,0 +1,22 @@ +langcode: en +status: true +dependencies: + config: + - comment.type.migrate_example_advanced_comment + - field.field.comment.migrate_example_advanced_comment.comment_body + module: + - text +id: comment.migrate_example_advanced_comment.default +targetEntityType: comment +bundle: migrate_example_advanced_comment +mode: default +content: + comment_body: + label: hidden + type: text_default + weight: 0 + settings: { } + third_party_settings: { } + links: + weight: 100 +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.default.yml new file mode 100644 index 000000000..90c620b9c --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.default.yml @@ -0,0 +1,33 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.migrate_example_producer.body + - field.field.node.migrate_example_producer.field_migrate_example_wine_regio + - node.type.migrate_example_producer + module: + - text + - user +id: node.migrate_example_producer.default +targetEntityType: node +bundle: migrate_example_producer +mode: default +content: + body: + label: hidden + type: text_default + weight: 101 + settings: { } + third_party_settings: { } + field_migrate_example_wine_regio: + weight: 102 + label: inline + settings: + link: true + third_party_settings: { } + type: entity_reference_label + links: + weight: 100 + settings: { } + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.teaser.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.teaser.yml new file mode 100644 index 000000000..ec5fcd544 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_producer.teaser.yml @@ -0,0 +1,27 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.migrate_example_producer.body + - field.field.node.migrate_example_producer.field_migrate_example_wine_regio + - node.type.migrate_example_producer + module: + - text + - user +id: node.migrate_example_producer.teaser +targetEntityType: node +bundle: migrate_example_producer +mode: teaser +content: + body: + label: hidden + type: text_summary_or_trimmed + weight: 101 + settings: + trim_length: 600 + third_party_settings: { } + links: + weight: 100 +hidden: + field_migrate_example_wine_regio: true diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.default.yml new file mode 100644 index 000000000..57ad1155e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.default.yml @@ -0,0 +1,88 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.migrate_example_wine.body + - field.field.node.migrate_example_wine.field_migrate_example_comments + - field.field.node.migrate_example_wine.field_migrate_example_adv_image + - field.field.node.migrate_example_wine.field_migrate_example_top_vintag + - field.field.node.migrate_example_wine.field_migrate_example_wine_best + - field.field.node.migrate_example_wine.field_migrate_example_wine_ratin + - field.field.node.migrate_example_wine.field_migrate_example_wine_regio + - field.field.node.migrate_example_wine.field_migrate_example_wine_var + - node.type.migrate_example_wine + module: + - comment + - image + - text + - user +id: node.migrate_example_wine.default +targetEntityType: node +bundle: migrate_example_wine +mode: default +content: + body: + label: hidden + type: text_default + weight: 101 + settings: { } + third_party_settings: { } + field_migrate_example_comments: + weight: 108 + label: hidden + settings: + pager_id: 0 + third_party_settings: { } + type: comment_default + field_migrate_example_adv_image: + weight: 105 + label: hidden + settings: + image_style: '' + image_link: '' + third_party_settings: { } + type: image + field_migrate_example_top_vintag: + weight: 107 + label: inline + settings: + thousand_separator: '' + prefix_suffix: true + third_party_settings: { } + type: number_integer + field_migrate_example_wine_best: + weight: 104 + label: inline + settings: + link: true + third_party_settings: { } + type: entity_reference_label + field_migrate_example_wine_ratin: + weight: 106 + label: inline + settings: + thousand_separator: '' + decimal_separator: . + scale: 2 + prefix_suffix: true + third_party_settings: { } + type: number_decimal + field_migrate_example_wine_regio: + weight: 103 + label: inline + settings: + link: true + third_party_settings: { } + type: entity_reference_label + field_migrate_example_wine_var: + weight: 102 + label: inline + settings: + link: true + third_party_settings: { } + type: entity_reference_label + links: + weight: 100 + settings: { } + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.teaser.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.teaser.yml new file mode 100644 index 000000000..85874f7c9 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.node.migrate_example_wine.teaser.yml @@ -0,0 +1,39 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - field.field.node.migrate_example_wine.body + - field.field.node.migrate_example_wine.field_migrate_example_comments + - field.field.node.migrate_example_wine.field_migrate_example_adv_image + - field.field.node.migrate_example_wine.field_migrate_example_top_vintag + - field.field.node.migrate_example_wine.field_migrate_example_wine_best + - field.field.node.migrate_example_wine.field_migrate_example_wine_ratin + - field.field.node.migrate_example_wine.field_migrate_example_wine_regio + - field.field.node.migrate_example_wine.field_migrate_example_wine_var + - node.type.migrate_example_wine + module: + - text + - user +id: node.migrate_example_wine.teaser +targetEntityType: node +bundle: migrate_example_wine +mode: teaser +content: + body: + label: hidden + type: text_summary_or_trimmed + weight: 101 + settings: + trim_length: 600 + third_party_settings: { } + links: + weight: 100 +hidden: + field_migrate_example_comments: true + field_migrate_example_adv_image: true + field_migrate_example_top_vintag: true + field_migrate_example_wine_best: true + field_migrate_example_wine_ratin: true + field_migrate_example_wine_regio: true + field_migrate_example_wine_var: true diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.taxonomy_term.migrate_example_wine_varieties.default.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.taxonomy_term.migrate_example_wine_varieties.default.yml new file mode 100644 index 000000000..b475708a7 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/core.entity_view_display.taxonomy_term.migrate_example_wine_varieties.default.yml @@ -0,0 +1,27 @@ +langcode: en +status: true +dependencies: + config: + - field.field.taxonomy_term.migrate_example_wine_varieties.field_variety_attributes + - taxonomy.vocabulary.migrate_example_wine_varieties + module: + - text +id: taxonomy_term.migrate_example_wine_varieties.default +targetEntityType: taxonomy_term +bundle: migrate_example_wine_varieties +mode: default +content: + description: + label: hidden + type: text_default + weight: 0 + settings: { } + third_party_settings: { } + field_variety_attributes: + type: string + weight: 0 + label: inline + settings: + link_to_entity: false + third_party_settings: { } +hidden: { } diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.comment.migrate_example_advanced_comment.comment_body.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.comment.migrate_example_advanced_comment.comment_body.yml new file mode 100644 index 000000000..456d6230f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.comment.migrate_example_advanced_comment.comment_body.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + config: + - comment.type.migrate_example_advanced_comment + - field.storage.comment.comment_body + module: + - text +id: comment.migrate_example_advanced_comment.comment_body +field_name: comment_body +entity_type: comment +bundle: migrate_example_advanced_comment +label: Comment +description: '' +required: true +translatable: true +default_value: { } +default_value_callback: '' +settings: { } +field_type: text_long diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.body.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.body.yml new file mode 100644 index 000000000..4ddb0abd5 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.body.yml @@ -0,0 +1,21 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.migrate_example_producer + module: + - text +id: node.migrate_example_producer.body +field_name: body +entity_type: node +bundle: migrate_example_producer +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true +field_type: text_with_summary diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.field_migrate_example_wine_regio.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.field_migrate_example_wine_regio.yml new file mode 100644 index 000000000..fa8b92a41 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_producer.field_migrate_example_wine_regio.yml @@ -0,0 +1,26 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_wine_regio + - node.type.migrate_example_producer + - taxonomy.vocabulary.migrate_example_wine_regions +id: node.migrate_example_producer.field_migrate_example_wine_regio +field_name: field_migrate_example_wine_regio +entity_type: node +bundle: migrate_example_producer +label: 'Migrate Example Wine Regions' +description: 'Select the region this wine comes from' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + migrate_example_wine_regions: migrate_example_wine_regions + sort: + field: _none + auto_create: false +field_type: entity_reference diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.body.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.body.yml new file mode 100644 index 000000000..b8c0cff34 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.body.yml @@ -0,0 +1,21 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.body + - node.type.migrate_example_wine + module: + - text +id: node.migrate_example_wine.body +field_name: body +entity_type: node +bundle: migrate_example_wine +label: Body +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: + display_summary: true +field_type: text_with_summary diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_adv_image.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_adv_image.yml new file mode 100644 index 000000000..8933c38dc --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_adv_image.yml @@ -0,0 +1,37 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_adv_image + - node.type.migrate_example_wine + module: + - image +id: node.migrate_example_wine.field_migrate_example_adv_image +field_name: field_migrate_example_adv_image +entity_type: node +bundle: migrate_example_wine +label: Image +description: 'Upload an image to go with this wine.' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + file_directory: field/migrate_example/image + file_extensions: 'png gif jpg jpeg' + max_filesize: '' + max_resolution: '' + min_resolution: '' + alt_field: true + alt_field_required: false + title_field: false + title_field_required: false + default_image: + uuid: '' + alt: '' + title: '' + width: null + height: null + handler: 'default:file' + handler_settings: { } +field_type: image diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_comments.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_comments.yml new file mode 100644 index 000000000..f50dcd772 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_comments.yml @@ -0,0 +1,32 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_comments + - node.type.migrate_example_wine + module: + - comment +id: node.migrate_example_wine.field_migrate_example_comments +field_name: field_migrate_example_comments +entity_type: node +bundle: migrate_example_wine +label: Comments +description: '' +required: false +translatable: false +default_value: + - + status: 2 + cid: 0 + last_comment_timestamp: 0 + last_comment_name: null + last_comment_uid: 0 + comment_count: 0 +default_value_callback: '' +settings: + default_mode: 1 + per_page: 50 + anonymous: 0 + form_location: true + preview: 1 +field_type: comment diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_top_vintag.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_top_vintag.yml new file mode 100644 index 000000000..5b95bb5e0 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_top_vintag.yml @@ -0,0 +1,22 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_top_vintag + - node.type.migrate_example_wine +id: node.migrate_example_wine.field_migrate_example_top_vintag +field_name: field_migrate_example_top_vintag +entity_type: node +bundle: migrate_example_wine +label: 'Recommended vintages' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + min: null + max: null + prefix: '' + suffix: '' +field_type: integer diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_best.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_best.yml new file mode 100644 index 000000000..224fa66df --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_best.yml @@ -0,0 +1,26 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_wine_best + - node.type.migrate_example_wine + - taxonomy.vocabulary.migrate_example_wine_best_with +id: node.migrate_example_wine.field_migrate_example_wine_best +field_name: field_migrate_example_wine_best +entity_type: node +bundle: migrate_example_wine +label: 'Migrate Example Wine Best With' +description: 'Enter any foods this wine may be paired with, separated by commas' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + migrate_example_wine_best_with: migrate_example_wine_best_with + sort: + field: _none + auto_create: false +field_type: entity_reference diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_ratin.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_ratin.yml new file mode 100644 index 000000000..5841eae0f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_ratin.yml @@ -0,0 +1,22 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_wine_ratin + - node.type.migrate_example_wine +id: node.migrate_example_wine.field_migrate_example_wine_ratin +field_name: field_migrate_example_wine_ratin +entity_type: node +bundle: migrate_example_wine +label: Rating +description: 'Rating on a 1-100 scale' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + min: !!float 1 + max: !!float 100 + prefix: '' + suffix: '' +field_type: decimal diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_regio.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_regio.yml new file mode 100644 index 000000000..67b3534f5 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_regio.yml @@ -0,0 +1,26 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_wine_regio + - node.type.migrate_example_wine + - taxonomy.vocabulary.migrate_example_wine_regions +id: node.migrate_example_wine.field_migrate_example_wine_regio +field_name: field_migrate_example_wine_regio +entity_type: node +bundle: migrate_example_wine +label: 'Migrate Example Wine Regions' +description: 'Select the region this wine comes from' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + migrate_example_wine_regions: migrate_example_wine_regions + sort: + field: _none + auto_create: false +field_type: entity_reference diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_var.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_var.yml new file mode 100644 index 000000000..28b81942d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.node.migrate_example_wine.field_migrate_example_wine_var.yml @@ -0,0 +1,26 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_migrate_example_wine_var + - node.type.migrate_example_wine + - taxonomy.vocabulary.migrate_example_wine_varieties +id: node.migrate_example_wine.field_migrate_example_wine_var +field_name: field_migrate_example_wine_var +entity_type: node +bundle: migrate_example_wine +label: 'Migrate Example Wine Varieties' +description: 'Select the variety of this wine' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + migrate_example_wine_varieties: migrate_example_wine_varieties + sort: + field: _none + auto_create: false +field_type: entity_reference diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.taxonomy_term.migrate_example_wine_varieties.field_variety_attributes.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.taxonomy_term.migrate_example_wine_varieties.field_variety_attributes.yml new file mode 100644 index 000000000..7164459f8 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.field.taxonomy_term.migrate_example_wine_varieties.field_variety_attributes.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.taxonomy_term.field_variety_attributes + - taxonomy.vocabulary.migrate_example_wine_varieties +id: taxonomy_term.migrate_example_wine_varieties.field_variety_attributes +field_name: field_variety_attributes +entity_type: taxonomy_term +bundle: migrate_example_wine_varieties +label: Attributes +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_adv_image.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_adv_image.yml new file mode 100644 index 000000000..62fc9b090 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_adv_image.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + module: + - file + - image + - node +id: node.field_migrate_example_adv_image +field_name: field_migrate_example_adv_image +entity_type: node +type: image +settings: + uri_scheme: public + default_image: + uuid: '' + alt: '' + title: '' + width: null + height: null + target_type: file + display_field: false + display_default: false +module: image +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_comments.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_comments.yml new file mode 100644 index 000000000..1d7b9f10a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_comments.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - comment + - node +id: node.field_migrate_example_comments +field_name: field_migrate_example_comments +entity_type: node +type: comment +settings: + comment_type: migrate_example_advanced_comment +module: comment +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_top_vintag.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_top_vintag.yml new file mode 100644 index 000000000..86b0c27b2 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_top_vintag.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node +id: node.field_migrate_example_top_vintag +field_name: field_migrate_example_top_vintag +entity_type: node +type: integer +settings: + unsigned: false + size: normal +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_best.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_best.yml new file mode 100644 index 000000000..9026e5881 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_best.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_migrate_example_wine_best +field_name: field_migrate_example_wine_best +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_ratin.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_ratin.yml new file mode 100644 index 000000000..fc3dbe9c7 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_ratin.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node +id: node.field_migrate_example_wine_ratin +field_name: field_migrate_example_wine_ratin +entity_type: node +type: decimal +settings: + precision: 10 + scale: 0 +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_regio.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_regio.yml new file mode 100644 index 000000000..3b2b16339 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_regio.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_migrate_example_wine_regio +field_name: field_migrate_example_wine_regio +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_var.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_var.yml new file mode 100644 index 000000000..cca7a39fc --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.node.field_migrate_example_wine_var.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_migrate_example_wine_var +field_name: field_migrate_example_wine_var +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.taxonomy_term.field_variety_attributes.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.taxonomy_term.field_variety_attributes.yml new file mode 100644 index 000000000..e5db23f20 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/field.storage.taxonomy_term.field_variety_attributes.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + module: + - taxonomy +id: taxonomy_term.field_variety_attributes +field_name: field_variety_attributes +entity_type: taxonomy_term +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_producer.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_producer.yml new file mode 100644 index 000000000..4d78fee87 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_producer.yml @@ -0,0 +1,10 @@ +langcode: en +status: true +dependencies: { } +name: 'Wine Producer' +type: migrate_example_producer +description: 'Wineries, vineyards, and large producers.' +help: '' +new_revision: false +preview_mode: 1 +display_submitted: true diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_wine.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_wine.yml new file mode 100644 index 000000000..6f442d5e6 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/node.type.migrate_example_wine.yml @@ -0,0 +1,10 @@ +langcode: en +status: true +dependencies: { } +name: Wine +type: migrate_example_wine +description: 'Wine is what we drink.' +help: '' +new_revision: false +preview_mode: 1 +display_submitted: true diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_position.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_position.yml new file mode 100644 index 000000000..6a79fc90f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_position.yml @@ -0,0 +1,10 @@ +id: migrate_example_advanced_position +plugin_id: 'migrate_example_advanced_position' +granularity: method +configuration: + GET: + supported_formats: + - json + - xml + supported_auth: + - cookie diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_items.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_items.yml new file mode 100644 index 000000000..bf2518a5f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_items.yml @@ -0,0 +1,10 @@ +id: migrate_example_advanced_variety_items +plugin_id: 'migrate_example_advanced_variety_items' +granularity: method +configuration: + GET: + supported_formats: + - json + - xml + supported_auth: + - cookie diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_list.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_list.yml new file mode 100644 index 000000000..f19dc60fe --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_list.yml @@ -0,0 +1,10 @@ +id: migrate_example_advanced_variety_list +plugin_id: 'migrate_example_advanced_variety_list' +granularity: method +configuration: + GET: + supported_formats: + - json + - xml + supported_auth: + - cookie diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_multiple.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_multiple.yml new file mode 100644 index 000000000..c8960369f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/rest.resource.migrate_example_advanced_variety_multiple.yml @@ -0,0 +1,10 @@ +id: migrate_example_advanced_variety_multiple +plugin_id: 'migrate_example_advanced_variety_multiple' +granularity: method +configuration: + GET: + supported_formats: + - json + - xml + supported_auth: + - cookie diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_best_with.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_best_with.yml new file mode 100644 index 000000000..51cb1c93e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_best_with.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +name: 'Migrate Example Wine Best With' +vid: migrate_example_wine_best_with +description: 'Foods the wine goes best with' +hierarchy: 0 +weight: 0 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_regions.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_regions.yml new file mode 100644 index 000000000..9ebbadfcd --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_regions.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +name: 'Migrate Example Wine Regions' +vid: migrate_example_wine_regions +description: 'Wine regions' +hierarchy: 0 +weight: 0 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_varieties.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_varieties.yml new file mode 100644 index 000000000..ca12aca5f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/config/install/taxonomy.vocabulary.migrate_example_wine_varieties.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +name: 'Migrate Example Wine Varieties' +vid: migrate_example_wine_varieties +description: 'Wine varieties' +hierarchy: 0 +weight: 0 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.info.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.info.yml new file mode 100644 index 000000000..992cff06e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.info.yml @@ -0,0 +1,18 @@ +type: module +name: Migrate Advanced Example Setup +description: 'Separate site configuration for the example from the actual migration.' +package: Migration +# core: 8.x +hidden: 1 +dependencies: + - drupal:comment + - drupal:image + - drupal:text + - drupal:taxonomy + - drupal:rest + +# Information added by Drupal.org packaging script on 2017-05-10 +version: '8.x-4.0-beta1' +core: '8.x' +project: 'migrate_plus' +datestamp: 1494450189 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.install b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.install new file mode 100644 index 000000000..3c585b19c --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/migrate_example_advanced_setup.install @@ -0,0 +1,895 @@ + 'Wines of the world', + 'fields' => [ + 'wineid' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Wine ID', + ], + 'name' => [ + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ], + 'body' => [ + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Full description of the wine.', + ], + 'excerpt' => [ + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Abstract for this wine.', + ], + 'accountid' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'ID of the author.', + ], + 'posted' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Original creation date', + ], + 'last_changed' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Last change date', + ], + 'variety' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Wine variety', + ], + 'region' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Wine region', + ], + 'rating' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Rating (100-point scale)', + ], + ], + 'primary key' => ['wineid'], + ]; +} + +function migrate_example_advanced_schema_updates() { + return array( + 'description' => 'Updated wine ratings', + 'fields' => [ + 'wineid' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Wine ID', + ], + 'rating' => [ + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Rating (100-point scale)', + ], + ], + 'primary key' => ['wineid'], + ); +} + +function migrate_example_advanced_schema_producer() { + return array( + 'description' => 'Wine producers of the world', + 'fields' => array( + 'producerid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Producer ID', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'body' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Full description of the producer.', + ), + 'excerpt' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Abstract for this producer.', + ), + 'accountid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Account ID of the author.', + ), + ), + 'primary key' => array('producerid'), + ); +} + +function migrate_example_advanced_schema_categories() { + return array( + 'description' => 'Categories', + 'fields' => array( + 'categoryid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'unsigned' => TRUE, + 'description' => 'Category ID', + ), + 'type' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Type of category: variety, region, best_with', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'details' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + ), + 'category_parent' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Parent category, if any', + ), + 'ordering' => array( + 'type' => 'int', + 'unsigned' => FALSE, + 'not null' => FALSE, + 'description' => 'Order in which to display categories', + ), + ), + 'primary key' => array('categoryid'), + ); +} + +function migrate_example_advanced_schema_vintages() { + return array( + 'description' => 'Wine vintages', + 'fields' => array( + 'wineid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Wine ID', + ), + 'vintage' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Vintage (year)', + ), + ), + 'primary key' => array('wineid', 'vintage'), + ); +} + +function migrate_example_advanced_schema_variety_updates() { + return array( + 'description' => 'Variety updates', + 'fields' => array( + 'categoryid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'unsigned' => TRUE, + 'description' => 'Category ID', + ), + 'details' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + ), + ), + 'primary key' => array('categoryid'), + ); +} + +function migrate_example_advanced_schema_category_wine() { + return array( + 'description' => 'Wine category assignments', + 'fields' => array( + 'wineid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Wine ID', + ), + 'categoryid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Category ID', + ), + ), + 'primary key' => array('categoryid', 'wineid'), + ); +} + +function migrate_example_advanced_schema_category_producer() { + return array( + 'description' => 'Producer category assignments', + 'fields' => array( + 'producerid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Producer ID', + ), + 'categoryid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Category ID', + ), + ), + 'primary key' => array('categoryid', 'producerid'), + ); +} + +function migrate_example_advanced_schema_comment() { + return array( + 'description' => 'Wine comments', + 'fields' => array( + 'commentid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Comment ID', + ), + 'wineid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Wine ID that is being commented upon', + ), + 'comment_parent' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Parent comment ID in case of comment replies.', + ), + 'subject' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment subject', + ), + 'body' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment body', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment name (if anon)', + ), + 'mail' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment email (if anon)', + ), + 'accountid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Account ID (if any).', + ), + 'commenthost' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'IP/domain of host posted from', + ), + 'userpage' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'User homepage', + ), + 'posted' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Date comment posted', + ), + 'lastchanged' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Date comment last changed', + ), + ), + 'primary key' => array('commentid'), + ); +} + +function migrate_example_advanced_schema_comment_updates() { + return array( + 'description' => 'Wine comment updates', + 'fields' => array( + 'commentid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Comment ID', + ), + 'subject' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Comment subject', + ), + ), + 'primary key' => array('commentid'), + ); +} + +function migrate_example_advanced_schema_account() { + return array( + 'description' => 'Wine accounts.', + 'fields' => array( + 'accountid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Account ID', + ), + 'status' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Blocked_Allowed', + ), + 'posted' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Registration date', + ), + 'last_access' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Last access date', + ), + 'last_login' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Last login date', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account name (for login)', + ), + 'sex' => array( + 'type' => 'char', + 'length' => 1, + 'not null' => FALSE, + 'description' => 'Gender', + ), + 'password' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account password (raw)', + ), + 'mail' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Account email', + ), + 'original_mail' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Original account email', + ), + 'sig' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Signature for comments', + ), + 'imageid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Image ID', + ), + 'positions' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Positions held', + ), + ), + 'primary key' => array('accountid'), + ); +} + +function migrate_example_advanced_schema_account_updates() { + return array( + 'description' => 'Wine account updates', + 'fields' => array( + 'accountid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Account ID', + ), + 'sex' => array( + 'type' => 'char', + 'length' => 1, + 'not null' => FALSE, + 'description' => 'Gender', + ), + ), + 'primary key' => array('accountid'), + ); +} + +function migrate_example_advanced_schema_blobs() { + return array( + 'description' => 'Wine blobs to be migrated to file entities', + 'fields' => array( + 'imageid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Image ID', + ), + 'imageblob' => array( + 'type' => 'blob', + 'size' => 'normal', + 'description' => 'binary image data', + ), + ), + 'primary key' => array('imageid'), + ); +} + +function migrate_example_advanced_schema_files() { + return array( + 'description' => 'Wine and account files', + 'fields' => array( + 'imageid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Image ID', + ), + 'url' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'Image URL', + ), + 'image_alt' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Image alt', + ), + 'image_title' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Image title', + ), + 'wineid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'Wine node this is associated with', + ), + ), + 'primary key' => array('imageid'), + ); +} + +function migrate_example_advanced_schema_table_source() { + return array( + 'description' => 'Source data to go into a custom Drupal table', + 'fields' => array( + 'fooid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Primary key', + ), + 'field1' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'First field', + ), + 'field2' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Second field', + ), + ), + 'primary key' => array('fooid'), + ); +} + +function migrate_example_advanced_schema_table_dest() { + return array( + 'description' => 'Custom Drupal table to receive source data directly', + 'fields' => array( + 'recordid' => array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Primary key', + ), + 'drupal_text' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'description' => 'First field', + ), + 'drupal_int' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'Second field', + ), + ), + 'primary key' => array('recordid'), + ); +} + +function migrate_example_advanced_data_wine() { + $fields = array('wineid', 'name', 'body', 'excerpt', 'accountid', + 'posted', 'last_changed', 'variety', 'region', 'rating'); + $query = db_insert('migrate_example_wine') + ->fields($fields); + $data = array( + array(1, 'Montes Classic Cabernet Sauvignon', 'Intense ruby-red color', 'Great!', 9, + strtotime('2010-01-02 03:04:05'), strtotime('2010-03-04 05:06:07'), 25, 17, 95), + array(2, 'Archeo Ruggero di Tasso Nero d\'Avola', 'Lots of berry character', 'Pair with red sauced dishes', 3, + strtotime('2010-09-03 18:23:58'), strtotime('2010-09-03 18:23:58'), 26, 2, 85), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_updates() { + $fields = array('wineid', 'rating'); + $query = db_insert('migrate_example_advanced_updates') + ->fields($fields); + $data = array( + array(1, 93), + array(2, NULL), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_producer() { + $fields = array('producerid', 'name', 'body', 'excerpt', 'accountid'); + $query = db_insert('migrate_example_advanced_producer') + ->fields($fields); + $data = array( + array(1, 'Montes', 'Fine Chilean winery', 'Great!', 9), + array(2, 'Archeo', 'Sicilia!', NULL, 3), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_account() { + $fields = array('accountid', 'status', 'posted', 'last_access', 'last_login', + 'name', 'sex', 'password', 'mail', 'original_mail', 'sig', 'imageid', 'positions'); + $query = db_insert('migrate_example_advanced_account') + ->fields($fields); + $data = array( + array(1, 1, '2010-03-30 10:31:05', '2010-04-30 18:25:24', '2010-04-30 14:01:02', + 'darren', 'M', 'dpass', 'ddarren@example.com', 'darren@example.com', + 'All about the Australians', NULL, '5'), + array(3, 0, '2007-03-15 10:31:05', '2007-06-10 04:11:38', '2007-06-10 04:11:38', + 'emily', 'F', 'insecure', 'emily@example.com', 'emily@example.com', + 'Sommelier to the stars', NULL, '18'), + array(9, 1, '2004-02-29 10:31:05', '2004-02-29 10:31:05', '2004-02-29 10:31:05', + 'fonzie', NULL, 'bike', 'thefonz@example.com', 'arthur@example.com', + 'Aaay!', 1, '5,18'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_account_updates() { + $fields = array('accountid', 'sex'); + $query = db_insert('migrate_example_advanced_account_updates') + ->fields($fields); + $data = array( + array(1, NULL), + array(3, 'M'), + array(9, 'F'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_comment() { + $fields = array('commentid', 'wineid', 'comment_parent', 'subject', 'body', + 'name', 'mail', 'accountid', 'commenthost', 'userpage', 'posted', 'lastchanged'); + $query = db_insert('migrate_example_advanced_comment') + ->fields($fields); + $data = array( + array(1, 1, NULL, 'im first', 'Tasty', 'grace', 'grace@example.com', 0, + '123.456.78.9', 'http:://grace.example.com/', + strtotime('2010-01-02 03:04:05'), strtotime('2010-04-05 06:07:08')), + array(2, 1, NULL, 'im second', 'Delicious', 'horace', 'horace@example.com', 0, + 'example.com', NULL, + strtotime('2010-02-02 03:04:05'), strtotime('2010-05-05 06:07:08')), + array(3, 1, NULL, 'im parent', 'Don\'t care for it', 'irene', 'irene@example.com', 0, + '254.0.2.5', 'http:://www.example.com/irene', + strtotime('2010-03-02 03:04:05'), strtotime('2010-03-02 03:04:05')), + array(4, 1, 3, 'im child', 'But it\'s so good!', 'emily', NULL, 3, + '58.29.126.1', 'http:://www.wine.com/', + strtotime('2010-01-02 03:04:05'), strtotime('2010-01-02 03:04:05')), + array(5, 1, 4, 'im grandchild', 'Right on, Emily!', 'thefonz@example.com', NULL, 9, + '123.456.78.9', NULL, + strtotime('2010-06-02 03:04:05'), strtotime('2010-06-02 03:04:05')), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_comment_updates() { + $fields = array('commentid', 'subject'); + $query = db_insert('migrate_example_advanced_comment_updates') + ->fields($fields); + $data = array( + array(1, 'I am first'), + array(2, 'I am second'), + array(3, 'I am parent'), + array(4, ''), + array(5, 'I am Spartacus'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_categories() { + $fields = array('categoryid', 'type', 'name', 'category_parent', 'details', 'ordering'); + $query = db_insert('migrate_example_advanced_categories') + ->fields($fields); + $data = array( + array(1, 'variety', 'White wine', NULL, 'White wines are generally simpler and sweeter than red', 3), + array(3, 'variety', 'Red wine', NULL, 'Red wines are generally more complex and "dry" than white', 1), + array(8, 'variety', 'Riesling', 1, 'Associated with Germany', 2), + array(9, 'variety', 'Chardonnay', 1, 'One of the most popular whites', 1), + array(13, 'variety', 'Merlot', 3, 'Very drinkable', 4), + array(14, 'variety', 'Syrah', 3, 'A.k.a. shiraz', -3), + array(25, 'variety', 'Cabernet Sauvignon', 3, 'A basic', -5), + array(26, 'variety', "Nero d'Avola", 3, 'Sicilian specialty', 2), + array(2, 'region', 'Italy', NULL, 'Largest producer of wine', 5), + array(11, 'region', 'Tuscany', 2, NULL, 2), + array(18, 'region', 'Chianti', 11, NULL, -1), + array(19, 'region', 'Elba', 11, NULL, 5), + array(4, 'region', 'France', NULL, 'C\'est bon', 6), + array(5, 'region', 'Bordeaux', 4, NULL, 1), + array(6, 'region', 'Barsac', 5, NULL, 3), + array(7, 'region', 'Pomerol', 5, NULL, 2), + array(16, 'region', 'Chile', NULL, NULL, 3), + array(17, 'region', 'Colchagua Valley', 16, NULL, 1), + array(20, 'region', 'California', NULL, NULL, 5), + array(21, 'region', 'Redwood Valley', 20, NULL, 1), + array(10, 'best_with', 'Beef', NULL, NULL, 5), + array(12, 'best_with', 'Pork', NULL, NULL, -3), + array(15, 'best_with', 'Chicken', NULL, NULL, -5), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_vintages() { + $fields = array('wineid', 'vintage'); + $query = db_insert('migrate_example_advanced_vintages') + ->fields($fields); + $data = array( + array(1, 2006), + array(1, 2007), + array(2, 2001), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_variety_updates() { + $fields = array('categoryid', 'details'); + $query = db_insert('migrate_example_advanced_variety_updates') + ->fields($fields); + $data = array( + array(1, 'White wines are simpler and sweeter than red'), + array(3, 'Red wines are generally more complex and dry than white'), + array(8, 'Usually associated with Germany'), + array(9, NULL), + array(13, 'Common, very drinakable'), + array(14, 'AKA Shiraz'), + array(25, 'Basic'), + array(26, 'A specialty of Sicily'), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_category_wine() { + $fields = array('wineid', 'categoryid'); + $query = db_insert('migrate_example_advanced_category_wine') + ->fields($fields); + $data = array( + array(1, 12), + array(1, 15), + array(2, 10), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_category_producer() { + $fields = array('producerid', 'categoryid'); + $query = db_insert('migrate_example_advanced_category_producer') + ->fields($fields); + $data = array( + array(1, 17), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_files() { + $fields = array('imageid', 'url', 'image_alt', 'image_title', 'wineid'); + $query = db_insert('migrate_example_advanced_files') + ->fields($fields); + $data = array( + array(1, 'http://placekitten.com/200/200', NULL, NULL, NULL), + array(2, 'http://cyrve.com/files/penguin.jpeg', 'Penguin alt', 'Penguin title', 1), + array(3, 'http://cyrve.com/files/rioja.jpeg', 'Rioja alt', 'Rioja title', 2), + array(4, 'http://cyrve.com/files/boutisse_0.jpeg', 'Boutisse alt', 'Boutisse title', 2), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_blobs() { + $blob = file_get_contents('core/misc/druplicon.png'); + $fields = array('imageid', 'imageblob'); + $query = db_insert('migrate_example_advanced_blobs') + ->fields($fields); + $data = array( + array(1, $blob), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} + +function migrate_example_advanced_data_table_source() { + $fields = array('fooid', 'field1', 'field2'); + $query = db_insert('migrate_example_advanced_table_source') + ->fields($fields); + $data = array( + array(3, 'Some sample data', 58), + array(15, 'Whatever', 2), + array(646, 'More sample data', 34989), + ); + foreach ($data as $row) { + $query->values(array_combine($fields, $row)); + } + $query->execute(); +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/PositionResource.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/PositionResource.php new file mode 100644 index 000000000..20fe34aad --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/PositionResource.php @@ -0,0 +1,44 @@ + 'wine_taster', 'name' => 'Wine Taster']; + $position2 = ['sourceid' => 'vintner', 'name' => 'Vintner']; + $data = ['position' => [$position1, $position2]]; + + $response = new ResourceResponse($data, 200); + return $response; + } + + /** + * {@inheritdoc} + */ + public function permissions() { + // Remove permissions so the resource is available to all. + return []; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyItems.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyItems.php new file mode 100644 index 000000000..a14986036 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyItems.php @@ -0,0 +1,72 @@ + [ + 'name' => 'Retsina', + 'parent' => 1, // categoryid for 'white'. + 'details' => 'Greek', + ], + 'trebbiano' => [ + 'name' => 'Trebbiano', + 'parent' => 1, // categoryid for 'white'. + 'details' => 'Italian', + ], + 'valpolicella' => [ + 'name' => 'Valpolicella', + 'parent' => 3, // categoryid for 'red'. + 'details' => 'Italian Venoto region', + ], + 'bardolino' => [ + 'name' => 'Bardolino', + 'parent' => 3, // categoryid for 'red'. + 'details' => 'Italian Venoto region', + ], + ]; + if (isset($varieties[$variety])) { + $data = ['variety' => $varieties[$variety]]; + } + else { + $data = []; + } + + $response = new ResourceResponse($data, 200); + return $response; + } + + /** + * {@inheritdoc} + */ + public function permissions() { + // Remove permissions so the resource is available to all. + return []; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyList.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyList.php new file mode 100644 index 000000000..bb4bb60cb --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/migrate_example_advanced_setup/src/Plugin/rest/resource/VarietyList.php @@ -0,0 +1,42 @@ + 'Amarone', + 'parent' => 3, // categoryid for 'red'. + 'details' => 'Italian Venoto region', + 'attributes' => [ + 'rich', + 'aromatic', + ], + ]; + $data['variety'][] = [ + 'name' => 'Barbaresco', + 'parent' => 3, // categoryid for 'red'. + 'details' => 'Italian Piedmont region', + 'attributes' => [ + 'smoky', + 'earthy', + ], + ]; + } + if (strtolower($type) != 'red') { + $data['variety'][] = [ + 'name' => 'Kir', + 'parent' => 1, // categoryid for 'white'. + 'details' => 'French Burgundy region', + 'attributes' => [], + ]; + $data['variety'][] = [ + 'name' => 'Pinot Grigio', + 'parent' => 1, // categoryid for 'white'. + 'details' => 'From the northeast of Italy', + 'attributes' => [ + 'fruity', + 'medium-bodied', + 'slightly sweet', + ], + ]; + } + + $response = new ResourceResponse($data, 200); + return $response; + } + + /** + * {@inheritdoc} + */ + public function permissions() { + // Remove permissions so the resource is available to all. + return []; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/src/Plugin/migrate/source/WineTerm.php b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/src/Plugin/migrate/source/WineTerm.php new file mode 100644 index 000000000..4bc143fcd --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_example_advanced/src/Plugin/migrate/source/WineTerm.php @@ -0,0 +1,50 @@ +select('migrate_example_advanced_categories', 'wc') + ->fields('wc', ['categoryid', 'type', 'name', 'details', 'category_parent', 'ordering']) + // This sort assures that parents are saved before children. + ->orderBy('category_parent', 'ASC'); + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'categoryid' => $this->t('Unique ID of the category'), + 'type' => $this->t('Category type corresponding to Drupal vocabularies'), + 'name' => $this->t('Category name'), + 'details' => $this->t('Description of the category'), + 'category_parent' => $this->t('ID of the parent category'), + 'ordering' => $this->t('Order in which to display this category'), + ]; + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + return ['categoryid' => ['type' => 'integer']]; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.info.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.info.yml new file mode 100644 index 000000000..6bd94f71f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.info.yml @@ -0,0 +1,13 @@ +type: module +name: Migrate Plus +description: 'Enhancements to core migration support' +package: Migration +# core: 8.x +dependencies: + - drupal:migrate (>=8.3) + +# Information added by Drupal.org packaging script on 2017-05-10 +version: '8.x-4.0-beta1' +core: '8.x' +project: 'migrate_plus' +datestamp: 1494450189 diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.install b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.install new file mode 100644 index 000000000..815b9876e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.install @@ -0,0 +1,38 @@ +select('config', 'c') + ->fields('c', ['name', 'data']) + ->condition('name', 'migrate.migration.%', 'LIKE') + ->execute(); + foreach ($migration_config as $migration) { + $data = unserialize($migration->data); + if (isset($data['third_party_settings']['migrate_plus']['migration_group'])) { + $data['migration_group'] = $data['third_party_settings']['migrate_plus']['migration_group']; + unset($data['third_party_settings']['migrate_plus']); + if (empty($data['third_party_settings'])) { + unset($data['third_party_settings']); + } + $new_name = str_replace('migrate.migration.', 'migrate_plus.migration.', $migration->name); + $database->update('config') + ->fields([ + 'name' => $new_name, + 'data' => serialize($data), + ]) + ->condition('name', $migration->name) + ->execute(); + } + } +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.module b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.module new file mode 100644 index 000000000..0dbddc473 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.module @@ -0,0 +1,87 @@ + $migration) { + // Add the default class where empty. + if (empty($migration['class'])) { + $migrations[$id]['class'] = 'Drupal\migrate\Plugin\Migration'; + } + + // For derived configuration entity-based migrations, strip the deriver + // prefix so we can reference migrations by the IDs they specify (i.e., + // the migration that specifies "id: temp" can be referenced as "temp" + // rather than "migration_config_deriver:temp"). + $prefix = 'migration_config_deriver:'; + if (strpos($id, $prefix) === 0) { + $new_id = substr($id, strlen($prefix)); + $migrations[$new_id] = $migrations[$id]; + unset($migrations[$id]); + $id = $new_id; + } + + // Integrate shared group configuration into the migration. + if (empty($migration['migration_group'])) { + $migration['migration_group'] = 'default'; + } + $group = MigrationGroup::load($migration['migration_group']); + if (empty($group)) { + // If the specified group does not exist, create it. Provide a little more + // for the 'default' group. + $group_properties = []; + $group_properties['id'] = $migration['migration_group']; + if ($migration['migration_group'] == 'default') { + $group_properties['label'] = 'Default'; + $group_properties['description'] = 'A container for any migrations not explicitly assigned to a group.'; + } + else { + $group_properties['label'] = $group_properties['id']; + $group_properties['description'] = ''; + } + $group = MigrationGroup::create($group_properties); + $group->save(); + } + $shared_configuration = $group->get('shared_configuration'); + if (empty($shared_configuration)) { + continue; + } + foreach ($shared_configuration as $key => $group_value) { + $migration_value = $migration[$key]; + // Where both the migration and the group provide arrays, replace + // recursively (so each key collision is resolved in favor of the + // migration). + if (is_array($migration_value) && is_array($group_value)) { + $merged_values = array_replace_recursive($group_value, $migration_value); + $migrations[$id][$key] = $merged_values; + } + // Where the group provides a value the migration doesn't, use the group + // value. + elseif (is_null($migration_value)) { + $migrations[$id][$key] = $group_value; + } + // Otherwise, the existing migration value overrides the group value. + } + } +} + +/** + * Implements hook_migrate_prepare_row(). + */ +function migrate_plus_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) { + \Drupal::service('event_dispatcher')->dispatch(MigrateEvents::PREPARE_ROW, new MigratePrepareRowEvent($row, $source, $migration)); +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.services.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.services.yml new file mode 100644 index 000000000..2ca3363c1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrate_plus.services.yml @@ -0,0 +1,10 @@ +services: + plugin.manager.migrate_plus.authentication: + class: Drupal\migrate_plus\AuthenticationPluginManager + parent: default_plugin_manager + plugin.manager.migrate_plus.data_fetcher: + class: Drupal\migrate_plus\DataFetcherPluginManager + parent: default_plugin_manager + plugin.manager.migrate_plus.data_parser: + class: Drupal\migrate_plus\DataParserPluginManager + parent: default_plugin_manager diff --git a/sites/all/modules/contrib/migrate/migrate_plus/migrations/migration_config_deriver.yml b/sites/all/modules/contrib/migrate/migrate_plus/migrations/migration_config_deriver.yml new file mode 100644 index 000000000..9fc597e7d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/migrations/migration_config_deriver.yml @@ -0,0 +1,6 @@ +id: migration_config_deriver +deriver: Drupal\migrate_plus\Plugin\MigrationConfigDeriver +# @todo: Remove if/when https://www.drupal.org/node/2797421 is fixed. +# Unused source configuration must be added to prevent errors. +source: + plugin: embedded_data diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Annotation/Authentication.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Annotation/Authentication.php new file mode 100644 index 000000000..910adb04c --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Annotation/Authentication.php @@ -0,0 +1,37 @@ +alterInfo('authentication_info'); + $this->setCacheBackend($cache_backend, 'migrate_plus_plugins_authentication'); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/DataFetcherPluginBase.php b/sites/all/modules/contrib/migrate/migrate_plus/src/DataFetcherPluginBase.php new file mode 100644 index 000000000..9e413fe10 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/DataFetcherPluginBase.php @@ -0,0 +1,32 @@ +alterInfo('data_fetcher_info'); + $this->setCacheBackend($cache_backend, 'migrate_plus_plugins_data_fetcher'); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginBase.php b/sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginBase.php new file mode 100644 index 000000000..a1e4c2dd3 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginBase.php @@ -0,0 +1,220 @@ +urls = $configuration['urls']; + $this->itemSelector = $configuration['item_selector']; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static($configuration, $plugin_id, $plugin_definition); + } + + /** + * Returns the initialized data fetcher plugin. + * + * @return \Drupal\migrate_plus\DataFetcherPluginInterface + * The data fetcher plugin. + */ + public function getDataFetcherPlugin() { + if (!isset($this->dataFetcherPlugin)) { + $this->dataFetcherPlugin = \Drupal::service('plugin.manager.migrate_plus.data_fetcher')->createInstance($this->configuration['data_fetcher_plugin'], $this->configuration); + } + return $this->dataFetcherPlugin; + } + + /** + * {@inheritdoc} + */ + public function rewind() { + $this->activeUrl = NULL; + $this->next(); + } + + /** + * Implementation of Iterator::next(). + */ + public function next() { + $this->currentItem = $this->currentId = NULL; + if (is_null($this->activeUrl)) { + if (!$this->nextSource()) { + // No data to import. + return; + } + } + // At this point, we have a valid open source url, try to fetch a row from + // it. + $this->fetchNextRow(); + // If there was no valid row there, try the next url (if any). + if (is_null($this->currentItem)) { + while ($this->nextSource()) { + $this->fetchNextRow(); + if ($this->valid()) { + break; + } + } + } + if ($this->valid()) { + foreach ($this->configuration['ids'] as $id_field_name => $id_info) { + $this->currentId[$id_field_name] = $this->currentItem[$id_field_name]; + } + } + } + + /** + * Opens the specified URL. + * + * @param $url + * URL to open. + * + * @return bool + * TRUE if the URL was successfully opened, FALSE otherwise. + */ + abstract protected function openSourceUrl($url); + + /** + * Retrieves the next row of data from the open source URL, populating + * currentItem. + */ + abstract protected function fetchNextRow(); + + /** + * Advances the data parser to the next source url. + * + * @return bool + * TRUE if a valid source URL was opened + */ + protected function nextSource() { + while ($this->activeUrl === NULL || (count($this->urls) - 1) > $this->activeUrl) { + if (is_null($this->activeUrl)) { + $this->activeUrl = 0; + } + else { + // Increment the activeUrl so we try to load the next source. + $this->activeUrl = $this->activeUrl + 1; + if ($this->activeUrl >= count($this->urls)) { + return FALSE; + } + } + + if ($this->openSourceUrl($this->urls[$this->activeUrl])) { + // We have a valid source. + return TRUE; + } + } + + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function current() { + return $this->currentItem; + } + + /** + * {@inheritdoc} + */ + public function key() { + return $this->currentId; + } + + /** + * {@inheritdoc} + */ + public function valid() { + return !empty($this->currentItem); + } + + /** + * {@inheritdoc} + */ + public function count() { + $count = 0; + foreach ($this as $item) { + $count++; + } + return $count; + } + + /** + * Return the selectors used to populate each configured field. + * + * @return string[] + * Array of selectors, keyed by field name. + */ + protected function fieldSelectors() { + $fields = []; + foreach ($this->configuration['fields'] as $field_info) { + if (isset($field_info['selector'])) { + $fields[$field_info['name']] = $field_info['selector']; + } + } + return $fields; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginInterface.php b/sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginInterface.php new file mode 100644 index 000000000..838ca9d36 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/DataParserPluginInterface.php @@ -0,0 +1,15 @@ +alterInfo('data_parser_info'); + $this->setCacheBackend($cache_backend, 'migrate_plus_plugins_data_parser'); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/Migration.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/Migration.php new file mode 100644 index 000000000..6359825cb --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/Migration.php @@ -0,0 +1,83 @@ +createInstance($plugin_id); + $entity_array['id'] = $new_plugin_id; + $entity_array['migration_tags'] = $migration_plugin->get('migration_tags'); + $entity_array['label'] = $migration_plugin->label(); + $entity_array['source'] = $migration_plugin->getSourceConfiguration(); + $entity_array['destination'] = $migration_plugin->getDestinationConfiguration(); + $entity_array['process'] = $migration_plugin->getProcess(); + $entity_array['migration_dependencies'] = $migration_plugin->getMigrationDependencies(); + $migration_entity = static::create($entity_array); + return $migration_entity; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroup.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroup.php new file mode 100644 index 000000000..519dbe241 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroup.php @@ -0,0 +1,77 @@ +condition('migration_group', $this->id()); + $names = $query->execute(); + + // Order the migrations according to their dependencies. + /** @var MigrationInterface[] $migrations */ + $migrations = \Drupal::entityTypeManager()->getStorage('migration')->loadMultiple($names); + + // Delete in reverse order, so dependencies are never violated. + $migrations = array_reverse($migrations); + + foreach ($migrations as $migration) { + $migration->delete(); + } + + // Finally, delete the group itself. + parent::delete(); + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + parent::calculateDependencies(); + // Make sure we save any explicit module dependencies. + if ($provider = $this->get('module')) { + $this->addDependency('module', $provider); + } + return $this->dependencies; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroupInterface.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroupInterface.php new file mode 100644 index 000000000..9dde2f2e4 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Entity/MigrationGroupInterface.php @@ -0,0 +1,12 @@ +row = $row; + $this->source = $source; + $this->migration = $migration; + } + + /** + * Gets the row object. + * + * @return \Drupal\migrate\Row + * The row object about to be imported. + */ + public function getRow() { + return $this->row; + } + + /** + * Gets the source plugin. + * + * @return \Drupal\migrate\Plugin\MigrateSourceInterface $source + * The source plugin firing the event. + */ + public function getSource() { + return $this->source; + } + + /** + * Gets the migration plugin. + * + * @return \Drupal\migrate\Plugin\MigrationInterface + * The migration entity being imported. + */ + public function getMigration() { + return $this->migration; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/MigrationConfigDeriver.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/MigrationConfigDeriver.php new file mode 100644 index 000000000..013544497 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/MigrationConfigDeriver.php @@ -0,0 +1,28 @@ +derivatives = []; + $migrations = Migration::loadMultiple(); + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $migration */ + foreach ($migrations as $id => $migration) { + $this->derivatives[$id] = $migration->toArray(); + } + return $this->derivatives; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/destination/Table.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/destination/Table.php new file mode 100755 index 000000000..64a6e8889 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/destination/Table.php @@ -0,0 +1,128 @@ +dbConnection = $connection; + $this->tableName = $configuration['table_name']; + $this->idFields = $configuration['id_fields']; + $this->fields = isset($configuration['fields']) ? $configuration['fields'] : []; + $this->supportsRollback = TRUE; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) { + $db_key = !empty($configuration['database_key']) ? $configuration['database_key'] : NULL; + + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $migration, + Database::getConnection('default', $db_key) + ); + } + + /** + * {@inheritdoc} + */ + public function getIds() { + if (empty($this->idFields)) { + throw new MigrateException('Id fields are required for a table destination'); + } + return $this->idFields; + } + + /** + * {@inheritdoc} + */ + public function fields(MigrationInterface $migration = NULL) { + return $this->fields; + } + + /** + * {@inheritdoc} + */ + public function import(Row $row, array $old_destination_id_values = []) { + $id = $row->getSourceIdValues(); + if (count($id) != count($this->idFields)) { + throw new MigrateSkipProcessException('All the id fields are required for a table migration.'); + } + + $values = $row->getDestination(); + + if ($this->fields) { + $values = array_intersect_key($values, $this->fields); + } + + $status = $this->dbConnection->merge($this->tableName) + ->key($id) + ->fields($values) + ->execute(); + + return $status ? $id : NULL; + } + + /** + * {@inheritdoc} + */ + public function rollback(array $destination_identifier) { + $delete = $this->dbConnection->delete($this->tableName); + foreach ($destination_identifier as $field => $value) { + $delete->condition($field, $value); + } + $delete->execute(); + } +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityGenerate.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityGenerate.php new file mode 100644 index 000000000..642ce0287 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityGenerate.php @@ -0,0 +1,101 @@ +generateEntity($value); + } + + return $result; + } + + /** + * Generates an entity for a given value. + * + * @param string $value + * Value to use in creation of the entity. + * + * @return int|string + * The entity id of the generated entity. + */ + protected function generateEntity($value) { + if (!empty($value)) { + $entity = $this->entityManager + ->getStorage($this->lookupEntityType) + ->create($this->entity($value)); + $entity->save(); + + return $entity->id(); + } + } + + /** + * Fabricate an entity. + * + * This is intended to be extended by implementing classes to provide for more + * dynamic default values, rather than just static ones. + * + * @param $value + * Primary value to use in creation of the entity. + * + * @return array + * Entity value array. + */ + protected function entity($value) { + $entity_values = [$this->lookupValueKey => $value]; + + if ($this->lookupBundleKey) { + $entity_values[$this->lookupBundleKey] = $this->lookupBundle; + } + + // Gather any static default values for properties/fields. + if (isset($this->configuration['default_values']) && is_array($this->configuration['default_values'])) { + foreach ($this->configuration['default_values'] as $key => $value) { + $entity_values[$key] = $value; + } + } + + return $entity_values; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityLookup.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityLookup.php new file mode 100644 index 000000000..abd341426 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/EntityLookup.php @@ -0,0 +1,249 @@ +migration = $migration; + $this->entityManager = $entityManager; + $this->selectionPluginManager = $selectionPluginManager; + $pluginIdParts = explode(':', $this->migration->getDestinationPlugin()->getPluginId()); + $this->destinationEntityType = empty($pluginIdParts[1]) ?: $pluginIdParts[1]; + $this->destinationBundleKey = !$this->destinationEntityType ?: $this->entityManager->getDefinition($this->destinationEntityType)->getKey('bundle'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition, MigrationInterface $migration = NULL) { + return new static( + $configuration, + $pluginId, + $pluginDefinition, + $migration, + $container->get('entity.manager'), + $container->get('plugin.manager.entity_reference_selection') + ); + } + + /** + * {@inheritdoc} + */ + public function transform($value, MigrateExecutableInterface $migrateExecutable, Row $row, $destinationProperty) { + // In case of subfields ('field_reference/target_id'), extract the field + // name only. + $parts = explode('/', $destinationProperty); + $destinationProperty = reset($parts); + $this->determineLookupProperties($destinationProperty); + + $this->destinationProperty = isset($this->configuration['destination_field']) ? $this->configuration['destination_field'] : NULL; + + return $this->query($value); + } + + /** + * Determine the lookup properties from config or target field configuration. + * + * @param string $destinationProperty + * The destination property currently worked on. This is only used together + * with the $row above. + */ + protected function determineLookupProperties($destinationProperty) { + if (!empty($this->configuration['value_key'])) { + $this->lookupValueKey = $this->configuration['value_key']; + } + if (!empty($this->configuration['bundle_key'])) { + $this->lookupBundleKey = $this->configuration['bundle_key']; + } + if (!empty($this->configuration['bundle'])) { + $this->lookupBundle = $this->configuration['bundle']; + } + if (!empty($this->configuration['entity_type'])) { + $this->lookupEntityType = $this->configuration['entity_type']; + } + + if (empty($this->lookupValueKey) || empty($this->lookupBundleKey) || empty($this->lookupBundle) || empty($this->lookupEntityType)) { + // See if we can introspect the lookup properties from the destination field. + if (!empty($this->migration->getProcess()[$this->destinationBundleKey][0]['default_value'])) { + $destinationEntityBundle = $this->migration->getProcess()[$this->destinationBundleKey][0]['default_value']; + $fieldConfig = $this->entityManager->getFieldDefinitions($this->destinationEntityType, $destinationEntityBundle)[$destinationProperty]->getConfig($destinationEntityBundle); + switch ($fieldConfig->getType()) { + case 'entity_reference': + if (empty($this->lookupBundle)) { + $handlerSettings = $fieldConfig->getSetting('handler_settings'); + $bundles = array_filter((array) $handlerSettings['target_bundles']); + if (count($bundles) == 1) { + $this->lookupBundle = reset($bundles); + } + // This was added in 8.1.x is not supported in 8.0.x. + elseif (!empty($handlerSettings['auto_create']) && !empty($handlerSettings['auto_create_bundle'])) { + $this->lookupBundle = reset($handlerSettings['auto_create_bundle']); + } + } + + // Make an assumption that if the selection handler can target more than + // one type of entity that we will use the first entity type. + $this->lookupEntityType = $this->lookupEntityType ?: reset($this->selectionPluginManager->createInstance($fieldConfig->getSetting('handler'))->getPluginDefinition()['entity_types']); + $this->lookupValueKey = $this->lookupValueKey ?: $this->entityManager->getDefinition($this->lookupEntityType)->getKey('label'); + $this->lookupBundleKey = $this->lookupBundleKey ?: $this->entityManager->getDefinition($this->lookupEntityType)->getKey('bundle'); + break; + + case 'file': + case 'image': + $this->lookupEntityType = 'file'; + $this->lookupValueKey = $this->lookupValueKey ?: 'uri'; + break; + + default: + throw new MigrateException('Destination field type ' . + $fieldConfig->getType(). 'is not a recognized reference type.'); + } + } + } + + // If there aren't enough lookup properties available by now, then bail. + if (empty($this->lookupValueKey)) { + throw new MigrateException('The entity_lookup plugin requires a value_key, none located.'); + } + if (!empty($this->lookupBundleKey) && empty($this->lookupBundle)) { + throw new MigrateException('The entity_lookup plugin found no bundle but destination entity requires one.'); + } + if (empty($this->lookupEntityType)) { + throw new MigrateException('The entity_lookup plugin requires a entity_type, none located.'); + } + } + + /** + * Checks for the existence of some value. + * + * @param $value + * The value to query. + * + * @return mixed|null + * Entity id if the queried entity exists. Otherwise NULL. + */ + protected function query($value) { + // Entity queries typically are case-insensitive. Therefore, we need to + // handle case sensitive filtering as a post-query step. By default, it + // filters case insensitive. Change to true if that is not the desired + // outcome. + $ignoreCase = !empty($this->configuration['ignore_case']) ?: FALSE; + + $multiple = is_array($value); + + $query = $this->entityManager->getStorage($this->lookupEntityType) + ->getQuery() + ->condition($this->lookupValueKey, $value, $multiple ? 'IN' : NULL); + + if ($this->lookupBundleKey) { + $query->condition($this->lookupBundleKey, $this->lookupBundle); + } + $results = $query->execute(); + + if (empty($results)) { + return NULL; + } + + // By default do a case-sensitive comparison. + if (!$ignoreCase) { + // Returns the entity's identifier. + foreach ($results as $k => $identifier) { + $result_value = $this->entityManager->getStorage($this->lookupEntityType)->load($identifier)->{$this->lookupValueKey}->value; + if (($multiple && !in_array($result_value, $value, TRUE)) || (!$multiple && $result_value !== $value)) { + unset($results[$k]); + } + } + } + + if ($multiple && !empty($this->destinationProperty)) { + array_walk($results, function (&$value) { + $value = [$this->destinationProperty => $value]; + }); + } + + return $multiple ? array_values($results) : reset($results); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/FileBlob.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/FileBlob.php new file mode 100644 index 000000000..cd838cb87 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/FileBlob.php @@ -0,0 +1,155 @@ + FALSE, + ); + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->fileSystem = $file_system; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('file_system') + ); + } + + /** + * {@inheritdoc} + */ + public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { + // If we're stubbing a file entity, return a URI of NULL so it will get + // stubbed by the general process. + if ($row->isStub()) { + return NULL; + } + list($destination, $blob) = $value; + + // Determine if we going to overwrite existing files or not touch them. + $replace = $this->getOverwriteMode(); + + // Attempt to save the file to avoid calling file_prepare_directory() any + // more than absolutely necessary. + if ($this->putFile($destination, $blob, $replace)) { + return $destination; + } + $dir = $this->getDirectory($destination); + if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY)) { + throw new MigrateSkipProcessException("Could not create directory '$dir'"); + } + if ($this->putFile($destination, $blob, $replace)) { + return $destination; + } + throw new MigrateSkipProcessException("Blob data could not be copied to $destination."); + } + + /** + * Try to save the file. + * + * @param string $destination + * The destination path or URI. + * @param string $blob + * The base64 encoded file contents. + * @param int $replace + * (optional) FILE_EXISTS_REPLACE (default) or FILE_EXISTS_ERROR, depending + * on the configuration. + * + * @return bool|string + * File path on success, FALSE on failure. + */ + protected function putFile($destination, $blob, $replace = FILE_EXISTS_REPLACE) { + if ($path = file_destination($destination, $replace)) { + if (file_put_contents($path, $blob)) { + return $path; + } + else { + return FALSE; + } + } + + // File was already copied. + return $destination; + } + + /** + * Determines how to handle file conflicts. + * + * @return int + * Either FILE_EXISTS_REPLACE (default) or FILE_EXISTS_ERROR, depending on + * the configuration. + */ + protected function getOverwriteMode() { + if (!empty($this->configuration['reuse'])) { + return FILE_EXISTS_ERROR; + } + + return FILE_EXISTS_REPLACE; + } + + /** + * Returns the directory component of a URI or path. + * + * For URIs like public://foo.txt, the full physical path of public:// + * will be returned, since a scheme by itself will trip up certain file + * API functions (such as file_prepare_directory()). + * + * @param string $uri + * The URI or path. + * + * @return string|false + * The directory component of the path or URI, or FALSE if it could not + * be determined. + */ + protected function getDirectory($uri) { + $dir = $this->fileSystem->dirname($uri); + if (substr($dir, -3) == '://') { + return $this->fileSystem->realpath($dir); + } + return $dir; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/Merge.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/Merge.php new file mode 100644 index 000000000..e646ca739 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/process/Merge.php @@ -0,0 +1,68 @@ +configuration['value']) && !array_key_exists('value', $this->configuration)) { + throw new MigrateException('Skip on value plugin is missing value configuration.'); + } + + if (is_array($this->configuration['value'])) { + foreach ($this->configuration['value'] as $skipValue) { + if ($this->compareValue($value, $skipValue, !isset($this->configuration['not_equals']))) { + throw new MigrateSkipRowException(); + } + } + } + elseif ($this->compareValue($value, $this->configuration['value'], !isset($this->configuration['not_equals']))) { + throw new MigrateSkipRowException(); + } + + return $value; + } + + /** + * {@inheritdoc} + */ + public function process($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { + if (empty($this->configuration['value']) && !array_key_exists('value', $this->configuration)) { + throw new MigrateException('Skip on value plugin is missing value configuration.'); + } + + if (is_array($this->configuration['value'])) { + foreach ($this->configuration['value'] as $skipValue) { + if ($this->compareValue($value, $skipValue, !isset($this->configuration['not_equals']))) { + throw new MigrateSkipProcessException(); + } + } + } + elseif ($this->compareValue($value, $this->configuration['value'], !isset($this->configuration['not_equals']))) { + throw new MigrateSkipProcessException(); + } + + return $value; + } + + /** + * Compare values to see if they are equal. + * + * @param $value + * Actual value + * @param $skipValue + * Value to compare against. + * @param $equal + * Compare as equal or not equal. + * + * @return bool + * True if the compare successfully, FALSE otherwise. + */ + protected function compareValue($value, $skipValue, $equal = TRUE) { + if ($equal) { + return (string) $value == (string) $skipValue; + } + + return (string) $value != (string) $skipValue; + + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/SourcePluginExtension.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/SourcePluginExtension.php new file mode 100644 index 000000000..19ca6a9a2 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/SourcePluginExtension.php @@ -0,0 +1,60 @@ +fields = $configuration['fields']; + $this->ids = $configuration['ids']; + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = []; + foreach ($this->fields as $field_info) { + $fields[$field_info['name']] = isset($field_info['label']) ? $field_info['label'] : $field_info['name']; + } + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + return $this->ids; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/Url.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/Url.php new file mode 100644 index 000000000..92f6d449d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate/source/Url.php @@ -0,0 +1,139 @@ +sourceUrls = $configuration['urls']; + + // Set a default Accept header. +/* $this->headers = array_merge(['Accept' => 'application/json'], + $configuration['headers'] ?: []);*/ + + // See if this is a paged response with next links. If so, add to the source_urls array. +/* foreach ( (array) $configuration['urls'] as $url) { + $this->sourceUrls += $this->getNextLinks($url); + }*/ + } + + /** + * Return a string representing the source URLs. + * + * @return string + * Comma-separated list of URLs being imported. + */ + public function __toString() { + // This could cause a problem when using a lot of urls, may need to hash. + $urls = implode(', ', $this->sourceUrls); + return $urls; + } + + /** + * Returns the initialized data parser plugin. + * + * @return \Drupal\migrate_plus\DataParserPluginInterface + * The data parser plugin. + */ + public function getDataParserPlugin() { + if (!isset($this->dataParserPlugin)) { + $this->dataParserPlugin = \Drupal::service('plugin.manager.migrate_plus.data_parser')->createInstance($this->configuration['data_parser_plugin'], $this->configuration); + } + return $this->dataParserPlugin; + } + + /** + * Creates and returns a filtered Iterator over the documents. + * + * @return \Iterator + * An iterator over the documents providing source rows that match the + * configured item_selector. + */ + protected function initializeIterator() { + return $this->getDataParserPlugin(); + } + + /** + * Collect an array of next links from a paged response. + */ +/* protected function getNextLinks($url) { + $urls = array(); + $more = TRUE; + while ($more == TRUE) { + $response = $this->dataParserPlugin->getDataFetcher()->getResponse($url); + if ($url = $this->getNextFromHeaders($response)) { + $urls[] = $url; + } + elseif ($url = $this->getNextFromLinks($response)) { + $urls[] = $url; + } + else { + $more = FALSE; + } + } + return $urls; + } +*/ + /** + * See if the next link is in a 'links' group in the response. + * + * @param \Psr\Http\Message\ResponseInterface $response + */ +/* protected function getNextFromLinks(ResponseInterface $response) { + $body = json_decode($response->getBody(), TRUE); + if (!empty($body['links']) && array_key_exists('next', $body['links'])) { + return $body['links']['next']; + } + return FALSE; + } +*/ + /** + * See if the next link is in the header. + * + * @param \Psr\Http\Message\ResponseInterface $response + */ +/* protected function getNextFromHeaders(ResponseInterface $response) { + $headers = $response->getHeader('Link'); + foreach ($headers as $header) { + $matches = array(); + preg_match('/^<(.*)>; rel="next"$/', $header, $matches); + if (!empty($matches) && !empty($matches[1])) { + return $matches[1]; + } + } + return FALSE; + } +*/ +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Basic.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Basic.php new file mode 100755 index 000000000..f1ca69ab6 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Basic.php @@ -0,0 +1,30 @@ + [ + $this->configuration['username'], + $this->configuration['password'], + ], + ]; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Digest.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Digest.php new file mode 100755 index 000000000..246653430 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/Digest.php @@ -0,0 +1,31 @@ + [ + $this->configuration['username'], + $this->configuration['password'], + 'digest', + ], + ]; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/OAuth2.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/OAuth2.php new file mode 100755 index 000000000..7415e72d1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/authentication/OAuth2.php @@ -0,0 +1,69 @@ + $handlerStack, + 'base_uri' => $this->configuration['base_uri'], + 'auth' => 'oauth2', + ]); + + switch ($this->configuration['grant_type']) { + case 'authorization_code': + $grant_type = new AuthorizationCode($client, $this->configuration); + break; + case 'client_credentials': + $grant_type = new ClientCredentials($client, $this->configuration); + break; + case 'urn:ietf:params:oauth:grant-type:jwt-bearer': + $grant_type = new JwtBearer($client, $this->configuration); + break; + case 'password': + $grant_type = new PasswordCredentials($client, $this->configuration); + break; + case 'refresh_token': + $grant_type = new RefreshToken($client, $this->configuration); + break; + default: + throw new MigrateException("Unrecognized grant_type {$this->configuration['grant_type']}."); + break; + } + $middleware = new OAuthMiddleware($client, $grant_type); + + return [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $middleware->getAccessToken()->getToken(), + ], + ]; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/File.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/File.php new file mode 100644 index 000000000..459c454bc --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/File.php @@ -0,0 +1,52 @@ +getResponse($url); + return $response; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/Http.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/Http.php new file mode 100755 index 000000000..7402126a9 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_fetcher/Http.php @@ -0,0 +1,104 @@ +httpClient = \Drupal::httpClient(); + } + + /** + * Returns the initialized authentication plugin. + * + * @return \Drupal\migrate_plus\AuthenticationPluginInterface + * The authentication plugin. + */ + public function getAuthenticationPlugin() { + if (!isset($this->authenticationPlugin)) { + $this->authenticationPlugin = \Drupal::service('plugin.manager.migrate_plus.authentication')->createInstance($this->configuration['authentication']['plugin'], $this->configuration['authentication']); + } + return $this->authenticationPlugin; + } + + /** + * {@inheritdoc} + */ + public function setRequestHeaders(array $headers) { + $this->headers = $headers; + } + + /** + * {@inheritdoc} + */ + public function getRequestHeaders() { + return !empty($this->headers) ? $this->headers : []; + } + + /** + * {@inheritdoc} + */ + public function getResponse($url) { + try { + $options = ['headers' => $this->getRequestHeaders()]; + if (!empty($this->configuration['authentication'])) { + $options = array_merge($options, $this->getAuthenticationPlugin()->getAuthenticationOptions()); + } + $response = $this->httpClient->get($url, $options); + if (empty($response)) { + throw new MigrateException('No response at ' . $url . '.'); + } + } + catch (RequestException $e) { + throw new MigrateException('Error message: ' . $e->getMessage() . ' at ' . $url .'.'); + } + return $response; + } + + /** + * {@inheritdoc} + */ + public function getResponseContent($url) { + $response = $this->getResponse($url); + return $response->getBody(); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Json.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Json.php new file mode 100755 index 000000000..c94444bc8 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Json.php @@ -0,0 +1,133 @@ +getDataFetcherPlugin()->getResponseContent($url); + + // Convert objects to associative arrays. + $source_data = json_decode($response, TRUE); + + // If json_decode() has returned NULL, it might be that the data isn't + // valid utf8 - see http://php.net/manual/en/function.json-decode.php#86997. + if (is_null($source_data)) { + $utf8response = utf8_encode($response); + $source_data = json_decode($utf8response); + } + + // Backwards-compatibility for depth selection. + if (is_int($this->itemSelector)) { + return $this->selectByDepth($source_data); + } + + // Otherwise, we're using xpath-like selectors. + $selectors = explode('/', trim($this->itemSelector, '/')); + foreach ($selectors as $selector) { + if (!empty($selector)) { + $source_data = $source_data[$selector]; + } + } + return $source_data; + } + + /** + * Get the source data for reading. + * + * @param array $raw_data + * Raw data from the JSON feed. + * + * @return array + * Selected items at the requested depth of the JSON feed. + */ + protected function selectByDepth(array $raw_data) { + // Return the results in a recursive iterator that can traverse + // multidimensional arrays. + $iterator = new \RecursiveIteratorIterator( + new \RecursiveArrayIterator($raw_data), + \RecursiveIteratorIterator::SELF_FIRST); + $items = []; + // Backwards-compatibility - an integer item_selector is interpreted as a + // depth. When there is an array of items at the expected depth, pull that + // array out as a distinct item. + $identifierDepth = $this->itemSelector; + $iterator->rewind(); + while ($iterator->valid()) { + $item = $iterator->current(); + if (is_array($item) && $iterator->getDepth() == $identifierDepth) { + $items[] = $item; + } + $iterator->next(); + } + return $items; + } + + /** + * {@inheritdoc} + */ + protected function openSourceUrl($url) { + // (Re)open the provided URL. + $source_data = $this->getSourceData($url); + $this->iterator = new \ArrayIterator($source_data); + return TRUE; + } + + /** + * {@inheritdoc} + */ + protected function fetchNextRow() { + $current = $this->iterator->current(); + if ($current) { + foreach ($this->fieldSelectors() as $field_name => $selector) { + $field_data = $current; + $field_selectors = explode('/', trim($selector, '/')); + foreach ($field_selectors as $field_selector) { + $field_data = $field_data[$field_selector]; + } + $this->currentItem[$field_name] = $field_data; + } + if (!empty($this->configuration['include_raw_data'])) { + $this->currentItem['raw'] = $current; + } + $this->iterator->next(); + } + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/SimpleXml.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/SimpleXml.php new file mode 100644 index 000000000..a33b6a086 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/SimpleXml.php @@ -0,0 +1,87 @@ +getDataFetcherPlugin()->getResponseContent($url); + $xml = simplexml_load_string($xml_data); + $this->registerNamespaces($xml); + $xpath = $this->configuration['item_selector']; + $this->matches = $xml->xpath($xpath); + foreach (libxml_get_errors() as $error) { + $error_string = self::parseLibXmlError($error); + throw new MigrateException($error_string); + } + return TRUE; + } + + /** + * {@inheritdoc} + */ + protected function fetchNextRow() { + $target_element = array_shift($this->matches); + + // If we've found the desired element, populate the currentItem and + // currentId with its data. + if ($target_element !== FALSE && !is_null($target_element)) { + foreach ($this->fieldSelectors() as $field_name => $xpath) { + foreach ($target_element->xpath($xpath) as $value) { + if ($value->children() && !trim((string) $value)) { + $this->currentItem[$field_name] = $value; + } + else { + $this->currentItem[$field_name][] = (string) $value; + } + } + } + // Reduce single-value results to scalars. + foreach ($this->currentItem as $field_name => $values) { + if (count($values) == 1) { + $this->currentItem[$field_name] = reset($values); + } + } + } + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Soap.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Soap.php new file mode 100755 index 000000000..60db90204 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Soap.php @@ -0,0 +1,123 @@ +function = $configuration['function']; + $this->parameters = $configuration['parameters']; + $this->responseType = $configuration['response_type']; + } + + /** + * {@inheritdoc} + * + * @throws \SoapFault + * If there's an error in a SOAP call. + * @throws \Drupal\migrate\MigrateException + * If we can't resolve the SOAP function or its response property. + */ + protected function openSourceUrl($url) { + // Will throw SoapFault if there's + $client = new \SoapClient($url); + // Determine the response property name. + $function_found = FALSE; + foreach ($client->__getFunctions() as $function_signature) { + // E.g., "GetWeatherResponse GetWeather(GetWeather $parameters)". + $response_type = strtok($function_signature, ' '); + $function_name = strtok('('); + if (strcasecmp($function_name, $this->function) === 0) { + $function_found = TRUE; + foreach ($client->__getTypes() as $type_info) { + // E.g., "struct GetWeatherResponse {\n string GetWeatherResult;\n}". + if (preg_match('|struct (.*?) {\s*[a-z]+ (.*?);|is', $type_info, $matches)) { + if ($matches[1] == $response_type) { + $response_property = $matches[2]; + } + } + } + break; + } + } + if (!$function_found) { + throw new MigrateException("SOAP function {$this->function} not found."); + } + elseif (!isset($response_property)) { + throw new MigrateException("Response property not found for SOAP function {$this->function}."); + } + $response = $client->{$this->function}($this->parameters); + $response_value = $response->$response_property; + switch ($this->responseType) { + case 'xml': + $xml = simplexml_load_string($response_value); + $this->iterator = new \ArrayIterator($xml->xpath($this->itemSelector)); + break; + case 'object': + $this->iterator = new \ArrayIterator($response_value->{$this->itemSelector}); + break; + case 'array': + $this->iterator = new \ArrayIterator($response_value[$this->itemSelector]); + break; + } + return TRUE; + } + + /** + * {@inheritdoc} + */ + protected function fetchNextRow() { + $current = $this->iterator->current(); + if ($current) { + foreach ($this->fieldSelectors() as $field_name => $selector) { + $this->currentItem[$field_name] = $current->$selector; + } + $this->iterator->next(); + } + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Xml.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Xml.php new file mode 100644 index 000000000..6c0806927 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/Xml.php @@ -0,0 +1,321 @@ + 'file', 1 => 'article']. + * + * @var array + */ + protected $elementsToMatch = []; + + /** + * An optional xpath predicate. + * + * Restricts the matching elements based on values in their children. Parsed + * from the element query at construct time. + * + * @var string + */ + protected $xpathPredicate = NULL; + + /** + * Array representing the path to the current element as we traverse the XML. + * + * For example, if in an XML string like '
...
' + * we are positioned within the article element, currentPath will be + * [0 => 'file', 1 => 'article']. + * + * @var array + */ + protected $currentPath = []; + + /** + * Retains all elements with a given name to support extraction from parents. + * + * This is a hack to support field extraction of values in parents + * of the 'context node' - ie, if $this->fields() has something like '..\nid'. + * Since we are using a streaming xml processor, it is too late to snoop + * around parent elements again once we've located an element of interest. So, + * grab elements with matching names and their depths, and refer back to it + * when building the source row. + * + * @var array + */ + protected $parentXpathCache = []; + + /** + * Hash of the element names that should be captured into $parentXpathCache. + * + * @var array + */ + protected $parentElementsOfInterest = []; + + /** + * Element name matching mode. + * + * When matching element names, whether to compare to the namespace-prefixed + * name, or the local name. + * + * @var bool + */ + protected $prefixedName = FALSE; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->reader = new \XMLReader(); + + // Suppress errors during parsing, so we can pick them up after. + libxml_use_internal_errors(TRUE); + + // Parse the element query. First capture group is the element path, second + // (if present) is the attribute. + preg_match_all('|^/([^\[]+)\[?(.*?)]?$|', $configuration['item_selector'], $matches); + $element_path = $matches[1][0]; + $this->elementsToMatch = explode('/', $element_path); + $predicate = $matches[2][0]; + if ($predicate) { + $this->xpathPredicate = $predicate; + } + + // If the element path contains any colons, it must be specifying + // namespaces, so we need to compare using the prefixed element + // name in next(). + if (strpos($element_path, ':')) { + $this->prefixedName = TRUE; + } + + foreach ($this->fieldSelectors() as $field_name => $xpath) { + $prefix = substr($xpath, 0, 3); + if ($prefix === '../') { + $this->parentElementsOfInterest[] = str_replace('../', '', $xpath); + } + elseif ($prefix === '..\\') { + $this->parentElementsOfInterest[] = str_replace('..\\', '', $xpath); + } + } + } + + /** + * Builds a \SimpleXmlElement rooted at the iterator's current location. + * + * The resulting SimpleXmlElement also contains any child nodes of the current + * element. + * + * @return \SimpleXmlElement|false + * A \SimpleXmlElement when the document is parseable, or false if a + * parsing error occurred. + * + * @throws MigrateException + */ + protected function getSimpleXml() { + $node = $this->reader->expand(); + if ($node) { + // We must associate the DOMNode with a DOMDocument to be able to import + // it into SimpleXML. Despite appearances, this is almost twice as fast as + // simplexml_load_string($this->readOuterXML()); + $dom = new \DOMDocument(); + $node = $dom->importNode($node, TRUE); + $dom->appendChild($node); + $sxml_elem = simplexml_import_dom($node); + $this->registerNamespaces($sxml_elem); + return $sxml_elem; + } + else { + foreach (libxml_get_errors() as $error) { + $error_string = self::parseLibXmlError($error); + throw new MigrateException($error_string); + } + return FALSE; + } + } + + /** + * {@inheritdoc} + */ + public function rewind() { + // Reset our path tracker. + $this->currentPath = []; + parent::rewind(); + } + + /** + * {@inheritdoc} + */ + protected function openSourceUrl($url) { + // (Re)open the provided URL. + $this->reader->close(); + + // Clear XML error buffer. Other Drupal code that executed during the + // migration may have polluted the error buffer and could create false + // positives in our error check below. We are only concerned with errors + // that occur from attempting to load the XML string into an object here. + libxml_clear_errors(); + + return $this->reader->open($url, NULL, \LIBXML_NOWARNING); + } + + /** + * {@inheritdoc} + */ + protected function fetchNextRow() { + $target_element = NULL; + + // Loop over each node in the XML file, looking for elements at a path + // matching the input query string (represented in $this->elementsToMatch). + while ($this->reader->read()) { + if ($this->reader->nodeType == \XMLReader::ELEMENT) { + if ($this->prefixedName) { + $this->currentPath[$this->reader->depth] = $this->reader->name; + if (in_array($this->reader->name, $this->parentElementsOfInterest)) { + $this->parentXpathCache[$this->reader->depth][$this->reader->name][] = $this->getSimpleXml(); + } + } + else { + $this->currentPath[$this->reader->depth] = $this->reader->localName; + if (in_array($this->reader->localName, $this->parentElementsOfInterest)) { + $this->parentXpathCache[$this->reader->depth][$this->reader->name][] = $this->getSimpleXml(); + } + } + if ($this->currentPath == $this->elementsToMatch) { + // We're positioned to the right element path - build the SimpleXML + // object to enable proper xpath predicate evaluation. + $target_element = $this->getSimpleXml(); + if ($target_element !== FALSE) { + if (empty($this->xpathPredicate) || $this->predicateMatches($target_element)) { + break; + } + } + } + } + elseif ($this->reader->nodeType == \XMLReader::END_ELEMENT) { + // Remove this element and any deeper ones from the current path. + foreach ($this->currentPath as $depth => $name) { + if ($depth >= $this->reader->depth) { + unset($this->currentPath[$depth]); + } + } + foreach ($this->parentXpathCache as $depth => $elements) { + if ($depth > $this->reader->depth) { + unset($this->parentXpathCache[$depth]); + } + } + } + } + + // If we've found the desired element, populate the currentItem and + // currentId with its data. + if ($target_element !== FALSE && !is_null($target_element)) { + foreach ($this->fieldSelectors() as $field_name => $xpath) { + $prefix = substr($xpath, 0, 3); + if (in_array($prefix, ['../', '..\\'])) { + $name = str_replace($prefix, '', $xpath); + $up = substr_count($xpath, $prefix); + $values = $this->getAncestorElements($up, $name); + } + else { + $values = $target_element->xpath($xpath); + } + foreach ($values as $value) { + // If the SimpleXMLElement doesn't render to a string of any sort, + // and has children then return the whole object for the process + // plugin or other row manipulation. + if ($value->children() && !trim((string) $value)) { + $this->currentItem[$field_name] = $value; + } + else { + $this->currentItem[$field_name][] = (string) $value; + } + } + } + // Reduce single-value results to scalars. + foreach ($this->currentItem as $field_name => $values) { + if (count($values) == 1) { + $this->currentItem[$field_name] = reset($values); + } + } + } + } + + /** + * Tests whether the iterator's xpath predicate matches the provided element. + * + * Has some limitations esp. in that it is easy to write predicates that + * reference things outside this SimpleXmlElement's tree, but "simpler" + * predicates should work as expected. + * + * @param \SimpleXMLElement $elem + * The element to test. + * + * @return bool + * True if the element matches the predicate, false if not. + */ + protected function predicateMatches(\SimpleXMLElement $elem) { + return !empty($elem->xpath('/*[' . $this->xpathPredicate . ']')); + } + + /** + * Gets an ancestor SimpleXMLElement, if the element name was registered. + * + * Gets the SimpleXMLElement some number of levels above the iterator + * having the given name, but only for element names that this + * Xml data parser was told to retain for future reference through the + * constructor's $parent_elements_of_interest. + * + * @param int $levels_up + * The number of levels back towards the root of the DOM tree to ascend + * before searching for the named element. + * @param string $name + * The name of the desired element. + * + * @return \SimpleXMLElement|false + * The element matching the level and name requirements, or false if it is + * not present or was not retained. + */ + public function getAncestorElements($levels_up, $name) { + if ($levels_up > 0) { + $levels_up *= -1; + } + $ancestor_depth = $this->reader->depth + $levels_up + 1; + if ($ancestor_depth < 0) { + return FALSE; + } + + if (array_key_exists($ancestor_depth, $this->parentXpathCache) && array_key_exists($name, $this->parentXpathCache[$ancestor_depth])) { + return $this->parentXpathCache[$ancestor_depth][$name]; + } + else { + return FALSE; + } + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/XmlTrait.php b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/XmlTrait.php new file mode 100644 index 000000000..e1a8aafb0 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/src/Plugin/migrate_plus/data_parser/XmlTrait.php @@ -0,0 +1,65 @@ +configuration['namespaces']) && is_array($this->configuration['namespaces'])) { + foreach ($this->configuration['namespaces'] as $prefix => $ns) { + $xml->registerXPathNamespace($prefix, $ns); + } + } + } + + /** + * Parses a LibXMLError to a error message string. + * + * @param \LibXMLError $error + * Error thrown by the XML. + * + * @return string + * Error message + */ + public static function parseLibXmlError(\LibXMLError $error) { + $error_code_name = 'Unknown Error'; + switch ($error->level) { + case LIBXML_ERR_WARNING: + $error_code_name = t('Warning'); + break; + + case LIBXML_ERR_ERROR: + $error_code_name = t('Error'); + break; + + case LIBXML_ERR_FATAL: + $error_code_name = t('Fatal Error'); + break; + } + + return t( + "@libxmlerrorcodename @libxmlerrorcode: @libxmlerrormessage\n" . + "Line: @libxmlerrorline\n" . + "Column: @libxmlerrorcolumn\n" . + "File: @libxmlerrorfile", + [ + '@libxmlerrorcodename' => $error_code_name, + '@libxmlerrorcode' => $error->code, + '@libxmlerrormessage' => trim($error->message), + '@libxmlerrorline' => $error->line, + '@libxmlerrorcolumn' => $error->column, + '@libxmlerrorfile' => (($error->file)) ? $error->file : NULL, + ] + ); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrateTableTest.php b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrateTableTest.php new file mode 100755 index 000000000..56c8b7ada --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrateTableTest.php @@ -0,0 +1,136 @@ +connection = Database::getConnection(); + + $this->connection->schema()->createTable(static::TABLE_NAME, [ + 'description' => 'Test table', + 'fields' => [ + 'data' => [ + 'type' => 'varchar', + 'length' => '32', + 'not null' => TRUE, + ], + 'data2' => [ + 'type' => 'varchar', + 'length' => '32', + 'not null' => TRUE, + ], + 'data3' => [ + 'type' => 'varchar', + 'length' => '32', + 'not null' => TRUE, + ], + ], + 'primary key' => ['data'], + ]); + } + + protected function tearDown() { + $this->connection->schema()->dropTable(static::TABLE_NAME); + parent::tearDown(); + } + + protected function getTableDestinationMigration() { + // Create a minimally valid migration with some source data. + $definition = [ + 'id' => 'migration_table_test', + 'migration_tags' => ['Testing'], + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + ['data' => 'dummy value', 'data2' => 'dummy2 value', 'data3' => 'dummy3 value'], + ['data' => 'dummy value2', 'data2' => 'dummy2 value2', 'data3' => 'dummy3 value2'], + ['data' => 'dummy value3', 'data2' => 'dummy2 value3', 'data3' => 'dummy3 value3'], + ], + 'ids' => [ + 'data' => ['type' => 'string'], + ], + ], + 'destination' => [ + 'plugin' => 'table', + 'table_name' => static::TABLE_NAME, + 'id_fields' => ['data' => ['type' => 'string']], + ], + 'process' => [ + 'data' => 'data', + 'data2' => 'data2', + 'data3' => 'data3', + ], + ]; + return $definition; + } + + /** + * Tests table destination. + */ + public function testTableDestination() { + $migration = \Drupal::service('plugin.manager.migration')->createStubMigration($this->getTableDestinationMigration()); + + $executable = new MigrateExecutable($migration, $this); + $executable->import(); + + $values = $this->connection->select(static::TABLE_NAME) + ->fields(static::TABLE_NAME) + ->execute() + ->fetchAllAssoc('data'); + + $this->assertEquals('dummy value', $values['dummy value']->data); + $this->assertEquals('dummy2 value', $values['dummy value']->data2); + $this->assertEquals('dummy2 value2', $values['dummy value2']->data2); + $this->assertEquals('dummy3 value3', $values['dummy value3']->data3); + $this->assertEquals(3, count($values)); + } + + public function testTableRollback() { + $this->testTableDestination(); + + /** @var MigrationInterface $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createStubMigration($this->getTableDestinationMigration()); + $executable = new MigrateExecutable($migration, $this); + $executable->import(); + + $values = $this->connection->select(static::TABLE_NAME) + ->fields(static::TABLE_NAME) + ->execute() + ->fetchAllAssoc('data'); + + $this->assertEquals('dummy value', $values['dummy value']->data); + $this->assertEquals(3, count($values)); + + // Now rollback. + $executable->rollback(); + $values = $this->connection->select(static::TABLE_NAME) + ->fields(static::TABLE_NAME) + ->execute() + ->fetchAllAssoc('data'); + + $this->assertEquals(0, count($values)); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationConfigEntityTest.php b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationConfigEntityTest.php new file mode 100644 index 000000000..386363a36 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationConfigEntityTest.php @@ -0,0 +1,52 @@ +pluginManager = \Drupal::service('plugin.manager.migration'); + } + + public function testCacheInvalidation() { + $config = Migration::create([ + 'id' => 'test', + 'label' => 'Label A', + 'migration_tags' => [], + 'source' => [], + 'destination' => [], + 'migration_dependencies' => [], + ]); + $config->save(); + + $this->assertTrue($this->pluginManager->getDefinition('test')); + $this->assertSame('Label A', $this->pluginManager->getDefinition('test')['label']); + + // Clear static cache in the plugin manager, the cache tag take care of the + // persistent cache. + $this->pluginManager->useCaches(FALSE); + $this->pluginManager->useCaches(TRUE); + + $config->set('label', 'Label B'); + $config->save(); + + $this->assertSame('Label B', $this->pluginManager->getDefinition('test')['label']); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationGroupTest.php b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationGroupTest.php new file mode 100644 index 000000000..4cdd55253 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/MigrationGroupTest.php @@ -0,0 +1,121 @@ + $group_id, + 'shared_configuration' => [ + 'migration_tags' => ['Drupal 6'], // In migration, so will be overridden. + 'source' => [ + 'constants' => [ + 'type' => 'image', // Not in migration, so will be added. + 'cardinality' => '1', // In migration, so will be overridden. + ], + ], + 'destination' => ['plugin' => 'field_storage_config'], // Not in migration, so will be added. + ], + ]; + $this->container->get('entity_type.manager')->getStorage('migration_group') + ->create($group_configuration)->save(); + + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $migration */ + $migration = $this->container->get('entity_type.manager') + ->getStorage('migration')->create([ + 'id' => 'specific_migration', + 'load' => [], + 'migration_group' => $group_id, + 'label' => 'Unaffected by the group', + 'migration_tags' => ['Drupal 7'], // Overrides group. + 'destination' => [], + 'source' => [], + 'process' => [], + 'migration_dependencies' => [], + ]); + $migration->set('source', [ + 'plugin' => 'empty', // Not in group, persists. + 'constants' => [ + 'entity_type' => 'user', // Not in group, persists. + 'cardinality' => '3', // Overrides group. + ], + ]); + $migration->save(); + + $expected_config = [ + 'migration_group' => $group_id, + 'label' => 'Unaffected by the group', + 'migration_tags' => ['Drupal 7'], + 'source' => [ + 'plugin' => 'empty', + 'constants' => [ + 'entity_type' => 'user', + 'type' => 'image', + 'cardinality' => '3', + ], + ], + 'destination' => ['plugin' => 'field_storage_config'], + ]; + /** @var \Drupal\migrate\Plugin\MigrationInterface $loaded_migration */ + $loaded_migration = $this->container->get('plugin.manager.migration') + ->createInstance('specific_migration'); + foreach ($expected_config as $key => $expected_value) { + $actual_value = $loaded_migration->get($key); + $this->assertEquals($expected_value, $actual_value); + } + } + + /** + * Test that deleting a group deletes its migrations. + */ + public function testDelete() { + /** @var MigrationGroupInterface $migration_group */ + $group_configuration = [ + 'id' => 'test_group', + ]; + $migration_group = $this->container->get('entity_type.manager') + ->getStorage('migration_group')->create($group_configuration); + $migration_group->save(); + + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $migration */ + $migration = $this->container->get('entity_type.manager') + ->getStorage('migration')->create([ + 'id' => 'specific_migration', + 'migration_group' => 'test_group', + 'migration_tags' => [], + 'load' => [], + 'destination' => [], + 'source' => [], + 'migration_dependencies' => [], + ]); + $migration->save(); + + /** @var \Drupal\migrate_plus\Entity\MigrationGroupInterface $loaded_migration_group */ + $loaded_migration_group = MigrationGroup::load('test_group'); + $loaded_migration_group->delete(); + + /** @var \Drupal\migrate_plus\Entity\MigrationInterface $loaded_migration */ + $loaded_migration = Migration::load('specific_migration'); + $this->assertNull($loaded_migration); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/Plugin/migrate/process/EntityGenerateTest.php b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/Plugin/migrate/process/EntityGenerateTest.php new file mode 100644 index 000000000..c7a340a5f --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Kernel/Plugin/migrate/process/EntityGenerateTest.php @@ -0,0 +1,328 @@ + $this->bundle, + 'name' => 'Page', + ]; + $node_type = NodeType::create($values); + $node_type->save(); + + $this->installEntitySchema('node'); + $this->installEntitySchema('taxonomy_term'); + $this->installEntitySchema('taxonomy_vocabulary'); + $this->installEntitySchema('user'); + $this->installSchema('system', ['sequences']); + $this->installSchema('user', 'users_data'); + $this->installConfig($this->modules); + + // Create a vocabulary. + $vocabulary = Vocabulary::create([ + 'name' => $this->vocabulary, + 'description' => $this->vocabulary, + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $vocabulary->save(); + + // Create a field. + $this->createEntityReferenceField( + 'node', + $this->bundle, + $this->fieldName, + 'Term reference', + 'taxonomy_term', + 'default', + ['target_bundles' => [$this->vocabulary]], + FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED + ); + + $this->migrationPluginManager = \Drupal::service('plugin.manager.migration'); + } + + /** + * Tests generating an entity. + * + * @dataProvider transformDataProvider + * + * @covers ::transform + */ + public function testTransform(array $definition, array $expected, array $preSeed = []) { + // Pre seed some test data. + foreach ($preSeed as $storageName => $values) { + /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ + $storage = $this->container + ->get('entity_type.manager') + ->getStorage($storageName); + $entity = $storage->create($values); + $entity->save(); + } + + /** @var Migration $migration */ + $migration = $this->migrationPluginManager->createStubMigration($definition); + /** @var EntityStorageBase $storage */ + $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage'); + $migrationExecutable = (new MigrateExecutable($migration, $this)); + $migrationExecutable->import(); + + foreach ($expected as $row) { + $entity = $storage->load($row['id']); + $properties = array_diff_key($row, array_flip(['id'])); + foreach ($properties as $property => $value) { + if (is_array($value)) { + foreach ($value as $key => $expectedValue) { + if (empty($expectedValue)) { + $this->assertEmpty($entity->{$property}->getValue(), "Expected value is empty but field $property is not empty."); + } + elseif ($entity->{$property}->getValue()) { + $this->assertEquals($expectedValue, $entity->{$property}[0]->entity->$key->value); + } + else { + $this->fail("Expected value: $expectedValue does not exist in $property."); + } + } + } + else { + $this->assertNotEmpty($entity, 'Entity with label ' . $row[$property] .' is empty'); + $this->assertEquals($row[$property], $entity->label()); + } + } + } + } + + /** + * Provides multiple migration definitions for "transform" test. + */ + public function transformDataProvider() { + return [ + 'no arguments' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => 'Apples', + ], + [ + 'id' => 2, + 'title' => 'content item 2', + 'term' => 'Bananas', + ], + [ + 'id' => 3, + 'title' => 'content item 3', + 'term' => 'Grapes', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + 'title' => 'title', + $this->fieldName => [ + 'plugin' => 'entity_generate', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => 1, + 'title' => 'content item 1', + $this->fieldName => [ + 'tid' => 2, + 'name' => 'Apples', + ], + ], + 'row 2' => [ + 'id' => 2, + 'title' => 'content item 2', + $this->fieldName => [ + 'tid' => 3, + 'name' => 'Bananas', + ], + ], + 'row 3' => [ + 'id' => 3, + 'title' => 'content item 3', + $this->fieldName => [ + 'tid' => 1, + 'name' => 'Grapes', + ], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + 'no arguments_lookup_only' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => 'Apples', + ], + [ + 'id' => 2, + 'title' => 'content item 2', + 'term' => 'Bananas', + ], + [ + 'id' => 3, + 'title' => 'content item 3', + 'term' => 'Grapes', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + 'title' => 'title', + $this->fieldName => [ + 'plugin' => 'entity_lookup', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => 1, + 'title' => 'content item 1', + $this->fieldName => [ + 'tid' => NULL, + 'name' => NULL, + ], + ], + 'row 2' => [ + 'id' => 2, + 'title' => 'content item 2', + $this->fieldName => [ + 'tid' => NULL, + 'name' => NULL, + ], + ], + 'row 3' => [ + 'id' => 3, + 'title' => 'content item 3', + $this->fieldName => [ + 'tid' => 1, + 'name' => 'Grapes', + ], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function display($message, $type = 'status') { + $this->assertTrue($type == 'status', $message); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Unit/process/SkipOnValueTest.php b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Unit/process/SkipOnValueTest.php new file mode 100644 index 000000000..aebcf6494 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_plus/tests/src/Unit/process/SkipOnValueTest.php @@ -0,0 +1,112 @@ +transform('86', $this->migrateExecutable, $this->row, 'destinationproperty'); + } + + /** + * @covers ::process + * @expectedException \Drupal\migrate\MigrateSkipProcessException + */ + public function testProcessSkipsOnMultipleValue() { + $configuration['method'] = 'process'; + $configuration['value'] = [1, 1, 2, 3, 5, 8]; + (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('5', $this->migrateExecutable, $this->row, 'destinationproperty'); + } + + /** + * @covers ::process + */ + public function testProcessBypassesOnNonValue() { + $configuration['method'] = 'process'; + $configuration['value'] = 'sourcevalue'; + $configuration['not_equals'] = TRUE; + $value = (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('sourcevalue', $this->migrateExecutable, $this->row, 'destinationproperty'); + $this->assertEquals($value, 'sourcevalue'); + $configuration['value'] = 86; + $value = (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('86', $this->migrateExecutable, $this->row, 'destinationproperty'); + $this->assertEquals($value, '86'); + } + + /** + * @covers ::process + */ + public function testProcessSkipsOnMultipleNonValue() { + $configuration['method'] = 'process'; + $configuration['value'] = [1, 1, 2, 3, 5, 8]; + $value = (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform(4, $this->migrateExecutable, $this->row, 'destinationproperty'); + $this->assertEquals($value, '4'); + } + + /** + * @covers ::row + * @expectedException \Drupal\migrate\MigrateSkipRowException + */ + public function testRowSkipsOnValue() { + $configuration['method'] = 'row'; + $configuration['value'] = 86; + (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('86', $this->migrateExecutable, $this->row, 'destinationproperty'); + } + + /** + * @covers ::row + */ + public function testRowBypassesOnNonValue() { + $configuration['method'] = 'row'; + $configuration['value'] = 'sourcevalue'; + $configuration['not_equals'] = TRUE; + $value = (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('sourcevalue', $this->migrateExecutable, $this->row, 'destinationproperty'); + $this->assertEquals($value, 'sourcevalue'); + $configuration['value'] = 86; + $value = (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('86', $this->migrateExecutable, $this->row, 'destinationproperty'); + $this->assertEquals($value, 86); + } + + /** + * @covers ::row + * @expectedException \Drupal\migrate\MigrateException + */ + public function testRequiredRowConfiguration() { + $configuration['method'] = 'row'; + (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('sourcevalue', $this->migrateExecutable, $this->row, 'destinationproperty'); + } + + /** + * @covers ::process + * @expectedException \Drupal\migrate\MigrateException + */ + public function testRequiredProcessConfiguration() { + $configuration['method'] = 'process'; + (new SkipOnValue($configuration, 'skip_on_value', [])) + ->transform('sourcevalue', $this->migrateExecutable, $this->row, 'destinationproperty'); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/LICENSE.txt b/sites/all/modules/contrib/migrate/migrate_tools/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/migrate/migrate_tools/README.txt b/sites/all/modules/contrib/migrate/migrate_tools/README.txt new file mode 100644 index 000000000..5f46ba08e --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/README.txt @@ -0,0 +1,15 @@ +The Migrate Tools module provides tools for running and managing Drupal 8 +migrations. + +Drush commands supported include: + +* migrate-status - Lists migrations and their status. +* migrate-import - Performs import operations. +* migrate-rollback - Performs rollback operations. +* migrate-stop - Cleanly stops a running operation. +* migrate-reset-status - Sets a migration status to Idle if it's gotten stuck. +* migrate-messages - Lists any messages associated with a migration import. + +The UI at this point provides a front-end equivalent to the migrate-status and +migrate-messages commands. It will be enhanced to allow running the other +operations, as well as provide the ability to create and alter migrations. diff --git a/sites/all/modules/contrib/migrate/migrate_tools/composer.json b/sites/all/modules/contrib/migrate/migrate_tools/composer.json new file mode 100644 index 000000000..227a90349 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/composer.json @@ -0,0 +1,11 @@ +{ + "name": "drupal/migrate_tools", + "description": "Tools to assist in developing and running migrations.", + "type": "drupal-module", + "require-dev": { + "drupal/coder": "^8" + }, + "license": "GPL-2.0+", + "require": {}, + "minimum-stability": "dev" +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/drush.services.yml b/sites/all/modules/contrib/migrate/migrate_tools/drush.services.yml new file mode 100644 index 000000000..ed0a3917b --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/drush.services.yml @@ -0,0 +1,6 @@ +services: + migrate_tools.commands: + class: \Drupal\migrate_tools\Commands\MigrateToolsCommands + arguments: ['@plugin.manager.migration', '@date.formatter', '@entity_type.manager', '@keyvalue'] + tags: + - { name: drush.command } diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.drush.inc b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.drush.inc new file mode 100644 index 000000000..4612874b6 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.drush.inc @@ -0,0 +1,524 @@ + 'List all migrations with current status.', + 'options' => [ + 'group' => 'A comma-separated list of migration groups to list', + 'tag' => 'Name of the migration tag to list', + 'names-only' => 'Only return names, not all the details (faster)', + ], + 'arguments' => [ + 'migration' => 'Restrict to a comma-separated list of migrations. Optional', + ], + 'examples' => [ + 'migrate-status' => 'Retrieve status for all migrations', + 'migrate-status --group=beer' => 'Retrieve status for all migrations in a given group', + 'migrate-status --tag=user' => 'Retrieve status for all migrations with a given tag', + 'migrate-status --group=beer --tag=user' => 'Retrieve status for all migrations in the beer group and with the user tag', + 'migrate-status beer_term,beer_node' => 'Retrieve status for specific migrations', + ], + 'drupal dependencies' => ['migrate_tools'], + 'aliases' => ['ms'], + ]; + + $items['migrate-import'] = [ + 'description' => 'Perform one or more migration processes.', + 'options' => [ + 'all' => 'Process all migrations.', + 'group' => 'A comma-separated list of migration groups to import', + 'tag' => 'Name of the migration tag to import', + 'limit' => 'Limit on the number of items to process in each migration', + 'feedback' => 'Frequency of progress messages, in items processed', + 'idlist' => 'Comma-separated list of IDs to import', + 'update' => ' In addition to processing unprocessed items from the source, update previously-imported items with the current data', + 'force' => 'Force an operation to run, even if all dependencies are not satisfied', + 'execute-dependencies' => 'Execute all dependent migrations first.', + ], + 'arguments' => [ + 'migration' => 'ID of migration(s) to import. Delimit multiple using commas.', + ], + 'examples' => [ + 'migrate-import --all' => 'Perform all migrations', + 'migrate-import --group=beer' => 'Import all migrations in the beer group', + 'migrate-import --tag=user' => 'Import all migrations with the user tag', + 'migrate-import --group=beer --tag=user' => 'Import all migrations in the beer group and with the user tag', + 'migrate-import beer_term,beer_node' => 'Import new terms and nodes', + 'migrate-import beer_user --limit=2' => 'Import no more than 2 users', + 'migrate-import beer_user --idlist=5' => 'Import the user record with source ID 5', + ], + 'drupal dependencies' => ['migrate_tools'], + 'aliases' => ['mi', 'mim'], + ]; + + $items['migrate-rollback'] = array( + 'description' => 'Rollback one or more migrations.', + 'options' => array( + 'all' => 'Process all migrations.', + 'group' => 'A comma-separated list of migration groups to rollback', + 'tag' => 'ID of the migration tag to rollback', + 'feedback' => 'Frequency of progress messages, in items processed', + ), + 'arguments' => array( + 'migration' => 'Name of migration(s) to rollback. Delimit multiple using commas.', + ), + 'examples' => array( + 'migrate-rollback --all' => 'Perform all migrations', + 'migrate-rollback --group=beer' => 'Rollback all migrations in the beer group', + 'migrate-rollback --tag=user' => 'Rollback all migrations with the user tag', + 'migrate-rollback --group=beer --tag=user' => 'Rollback all migrations in the beer group and with the user tag', + 'migrate-rollback beer_term,beer_node' => 'Rollback imported terms and nodes', + ), + 'drupal dependencies' => array('migrate_tools'), + 'aliases' => array('mr'), + ); + + $items['migrate-stop'] = [ + 'description' => 'Stop an active migration operation.', + 'arguments' => [ + 'migration' => 'ID of migration to stop', + ], + 'drupal dependencies' => ['migrate_tools'], + 'aliases' => ['mst'], + ]; + + $items['migrate-reset-status'] = [ + 'description' => 'Reset a active migration\'s status to idle.', + 'arguments' => [ + 'migration' => 'ID of migration to reset', + ], + 'drupal dependencies' => ['migrate_tools'], + 'aliases' => ['mrs'], + ]; + + $items['migrate-messages'] = [ + 'description' => 'View any messages associated with a migration.', + 'arguments' => [ + 'migration' => 'ID of the migration', + ], + 'options' => [ + 'csv' => 'Export messages as a CSV' + ], + 'examples' => [ + 'migrate-messages MyNode' => 'Show all messages for the MyNode migration', + ], + 'drupal dependencies' => ['migrate_tools'], + 'aliases' => ['mmsg'], + ]; + + $items['migrate-fields-source'] = [ + 'description' => 'List the fields available for mapping in a source.', + 'arguments' => [ + 'migration' => 'ID of the migration', + ], + 'examples' => [ + 'migrate-fields-source my_node' => 'List fields for the source in the my_node migration', + ], + 'drupal dependencies' => ['migrate_tools'], + 'aliases' => ['mfs'], + ]; + + return $items; +} + +/** + * @param string $migration_names + */ +function drush_migrate_tools_migrate_status($migration_names = '') { + $names_only = drush_get_option('names-only'); + + $migrations = drush_migrate_tools_migration_list($migration_names); + + $table = []; + // Take it one group at a time, listing the migrations within each group. + foreach ($migrations as $group_id => $migration_list) { + $group = MigrationGroup::load($group_id); + $group_name = !empty($group) ? "{$group->label()} ({$group->id()})" : $group_id; + if ($names_only) { + $table[] = [ + dt('Group: @name', array('@name' => $group_name)) + ]; + } + else { + $table[] = [ + dt('Group: @name', array('@name' => $group_name)), + dt('Status'), + dt('Total'), + dt('Imported'), + dt('Unprocessed'), + dt('Last imported'), + ]; + } + foreach ($migration_list as $migration_id => $migration) { + try { + $map = $migration->getIdMap(); + $imported = $map->importedCount(); + $source_plugin = $migration->getSourcePlugin(); + } + catch (Exception $e) { + drush_log(dt('Failure retrieving information on @migration: @message', + ['@migration' => $migration_id, '@message' => $e->getMessage()])); + continue; + } + if ($names_only) { + $table[] = [$migration_id]; + } + else { + try { + $source_rows = $source_plugin->count(); + // -1 indicates uncountable sources. + if ($source_rows == -1) { + $source_rows = dt('N/A'); + $unprocessed = dt('N/A'); + } + else { + $unprocessed = $source_rows - $map->processedCount(); + } + } + catch (Exception $e) { + drush_print($e->getMessage()); + drush_log(dt('Could not retrieve source count from @migration: @message', + ['@migration' => $migration_id, '@message' => $e->getMessage()])); + $source_rows = dt('N/A'); + $unprocessed = dt('N/A'); + } + + $status = $migration->getStatusLabel(); + $migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported'); + $last_imported = $migrate_last_imported_store->get($migration->id(), FALSE); + if ($last_imported) { + /** @var DateFormatter $date_formatter */ + $date_formatter = \Drupal::service('date.formatter'); + $last_imported = $date_formatter->format($last_imported / 1000, + 'custom', 'Y-m-d H:i:s'); + } + else { + $last_imported = ''; + } + $table[] = [$migration_id, $status, $source_rows, $imported, $unprocessed, $last_imported]; + } + } + } + drush_print_table($table); +} + +/** + * @param string $migration_names + */ +function drush_migrate_tools_migrate_import($migration_names = '') { + $group_names = drush_get_option('group'); + $tag_names = drush_get_option('tag'); + $all = drush_get_option('all'); + + // Display a depreciation message if "mi" alias is used. + $args = drush_get_arguments(); + if ($args[0] === 'mi') { + drush_log('The \'mi\' alias is deprecated and will no longer work with Drush 9. Consider the use of \'mim\' alias instead.', 'warning'); + } + + $options = []; + if (!$all && !$group_names && !$migration_names && !$tag_names) { + drush_set_error('MIGRATE_ERROR', dt('You must specify --all, --group, --tag or one or more migration names separated by commas')); + return; + } + + foreach (['limit', 'feedback', 'idlist', 'update', 'force'] as $option) { + if (drush_get_option($option)) { + $options[$option] = drush_get_option($option); + } + } + + $migrations = drush_migrate_tools_migration_list($migration_names); + if (empty($migrations)) { + drush_log(dt('No migrations found.'), 'error'); + } + + // Take it one group at a time, importing the migrations within each group. + foreach ($migrations as $group_id => $migration_list) { + array_walk($migration_list, '_drush_migrate_tools_execute_migration', $options); + } +} + +/** + * Executes a single migration. If the --execute-dependencies option was given, + * the migration's dependencies will also be executed first. + * + * @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 + * Additional options for the migration. + */ +function _drush_migrate_tools_execute_migration(MigrationInterface $migration, $migration_id, array $options = []) { + $log = new DrushLogMigrateMessage(); + + if (drush_get_option('execute-dependencies')) { + if ($required_IDS = $migration->get('requirements')) { + $manager = \Drupal::service('plugin.manager.migration'); + $required_migrations = $manager->createInstances($required_IDS); + $dependency_options = array_merge($options, ['is_dependency' => TRUE]); + array_walk($required_migrations, __FUNCTION__, $dependency_options); + } + } + if (!empty($options['force'])) { + $migration->set('requirements', []); + } + if (!empty($options['update'])) { + $migration->getIdMap()->prepareUpdate(); + } + $executable = new MigrateExecutable($migration, $log, $options); + // drush_op() provides --simulate support + drush_op(array($executable, 'import')); + if ($count = $executable->getFailedCount()) { + // Nudge Drush to use a non-zero exit code. + drush_set_error('MIGRATE_ERROR', dt('!name Migration - !count failed.', array('!name' => $migration_id, '!count' => $count))); + } +} + +/** + * @param string $migration_names + */ +function drush_migrate_tools_migrate_rollback($migration_names = '') { + $group_names = drush_get_option('group'); + $tag_names = drush_get_option('tag'); + $all = drush_get_option('all'); + $options = []; + if (!$all && !$group_names && !$migration_names && !$tag_names) { + drush_set_error('MIGRATE_ERROR', dt('You must specify --all, --group, --tag, or one or more migration names separated by commas')); + return; + } + + if (drush_get_option('feedback')) { + $options['feedback'] = drush_get_option('feedback'); + } + + $log = new DrushLogMigrateMessage(); + + $migrations = drush_migrate_tools_migration_list($migration_names); + if (empty($migrations)) { + drush_log(dt('No migrations found.'), 'error'); + } + + // Take it one group at a time, rolling back the migrations within each group. + foreach ($migrations as $group_id => $migration_list) { + // Roll back in reverse order. + $migration_list = array_reverse($migration_list); + foreach ($migration_list as $migration_id => $migration) { + $executable = new MigrateExecutable($migration, $log, $options); + // drush_op() provides --simulate support. + drush_op(array($executable, 'rollback')); + } + } +} + +/** + * @param string $migration_id + */ +function drush_migrate_tools_migrate_stop($migration_id = '') { + /** @var MigrationInterface $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); + if ($migration) { + $status = $migration->getStatus(); + switch ($status) { + case MigrationInterface::STATUS_IDLE: + drush_log(dt('Migration @id is idle', ['@id' => $migration_id]), 'warning'); + break; + case MigrationInterface::STATUS_DISABLED: + drush_log(dt('Migration @id is disabled', ['@id' => $migration_id]), 'warning'); + break; + case MigrationInterface::STATUS_STOPPING: + drush_log(dt('Migration @id is already stopping', ['@id' => $migration_id]), 'warning'); + break; + default: + $migration->interruptMigration(MigrationInterface::RESULT_STOPPED); + drush_log(dt('Migration @id requested to stop', ['@id' => $migration_id]), 'success'); + break; + } + } + else { + drush_log(dt('Migration @id does not exist', ['@id' => $migration_id]), 'error'); + } +} + +/** + * @param string $migration_id + */ +function drush_migrate_tools_migrate_reset_status($migration_id = '') { + /** @var MigrationInterface $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); + if ($migration) { + $status = $migration->getStatus(); + if ($status == MigrationInterface::STATUS_IDLE) { + drush_log(dt('Migration @id is already Idle', ['@id' => $migration_id]), 'warning'); + } + else { + $migration->setStatus(MigrationInterface::STATUS_IDLE); + drush_log(dt('Migration @id reset to Idle', ['@id' => $migration_id]), 'status'); + } + } + else { + drush_log(dt('Migration @id does not exist', ['@id' => $migration_id]), 'error'); + } +} + +/** + * @param string $migration_id + */ +function drush_migrate_tools_migrate_messages($migration_id) { + /** @var MigrationInterface $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); + if ($migration) { + $map = $migration->getIdMap(); + $first = TRUE; + $table = []; + foreach ($map->getMessageIterator() as $row) { + unset($row->msgid); + if ($first) { + // @todo: Ideally, replace sourceid* with source key names. Or, should + // getMessageIterator() do that? + foreach ($row as $column => $value) { + $table[0][] = $column; + } + $first = FALSE; + } + $table[] = (array)$row; + } + if (empty($table)) { + drush_log(dt('No messages for this migration'), 'status'); + } + else { + if (drush_get_option('csv')) { + foreach ($table as $row) { + fputcsv(STDOUT, $row); + } + } + else { + $widths = []; + foreach ($table[0] as $header) { + $widths[] = strlen($header) + 1; + } + drush_print_table($table, TRUE, $widths); + } + } + } + else { + drush_log(dt('Migration @id does not exist', ['@id' => $migration_id]), 'error'); + } +} + +/** + * @param string $migration_id + */ +function drush_migrate_tools_migrate_fields_source($migration_id) { + /** @var MigrationInterface $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id); + if ($migration) { + $source = $migration->getSourcePlugin(); + $table = []; + foreach ($source->fields() as $machine_name => $description) { + $table[] = [strip_tags($description), $machine_name]; + } + drush_print_table($table); + } + else { + drush_log(dt('Migration @id does not exist', ['@id' => $migration_id]), 'error'); + } +} + +/** + * Retrieve a list of active migrations. + * + * @param string $migration_ids + * Comma-separated list of migrations - if present, return only these migrations. + * + * @return 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. + */ +function drush_migrate_tools_migration_list($migration_ids = '') { + // Filter keys must match the migration configuration property name. + $filter['migration_group'] = drush_get_option('group') ? explode(',', drush_get_option('group')) : []; + $filter['migration_tags'] = drush_get_option('tag') ? explode(',', drush_get_option('tag')) : []; + + $manager = \Drupal::service('plugin.manager.migration'); + $plugins = $manager->createInstances([]); + $matched_migrations = []; + + // Get the set of migrations that may be filtered. + if (empty($migration_ids)) { + $matched_migrations = $plugins; + } + else { + // Get the requested migrations. + $migration_ids = explode(',', Unicode::strtolower($migration_ids)); + foreach ($plugins as $id => $migration) { + if (in_array(Unicode::strtolower($id), $migration_ids)) { + $matched_migrations[$id] = $migration; + } + } + } + + // Do not return any migrations which fail to meet requirements. + /** @var \Drupal\migrate\Plugin\Migration $migration */ + foreach ($matched_migrations as $id => $migration) { + if ($migration->getSourcePlugin() instanceof RequirementsInterface) { + try { + $migration->getSourcePlugin()->checkRequirements(); + } + catch (RequirementsException $e) { + unset($matched_migrations[$id]); + } + } + } + + // Filters the matched migrations if a group or a tag has been input. + if (!empty($filter['migration_group']) || !empty($filter['migration_tags'])) { + // Get migrations in any of the specified groups and with any of the + // specified tags. + foreach ($filter as $property => $values) { + if (!empty($values)) { + $filtered_migrations = []; + foreach ($values as $search_value) { + foreach ($matched_migrations as $id => $migration) { + // Cast to array because migration_tags can be an array. + $configured_values = (array) $migration->get($property); + $configured_id = (in_array($search_value, $configured_values)) ? $search_value : 'default'; + if (empty($search_value) || $search_value == $configured_id) { + if (empty($migration_ids) || in_array(Unicode::strtolower($id), $migration_ids)) { + $filtered_migrations[$id] = $migration; + } + } + } + } + $matched_migrations = $filtered_migrations; + } + } + } + + // Sort the matched migrations by group. + if (!empty($matched_migrations)) { + foreach ($matched_migrations as $id => $migration) { + $configured_group_id = empty($migration->get('migration_group')) ? 'default' : $migration->get('migration_group'); + $migrations[$configured_group_id][$id] = $migration; + } + } + return isset($migrations) ? $migrations : []; +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.info.yml b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.info.yml new file mode 100644 index 000000000..3abaf73ee --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.info.yml @@ -0,0 +1,14 @@ +type: module +name: Migrate Tools +description: 'Tools to assist in developing and running migrations.' +package: Migration +# core: 8.x +dependencies: + - drupal:migrate (>=8.3) + - migrate_plus:migrate_plus + +# Information added by Drupal.org packaging script on 2017-11-17 +version: '8.x-4.0-beta1+5-dev' +core: '8.x' +project: 'migrate_tools' +datestamp: 1510918687 diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.action.yml b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.action.yml new file mode 100644 index 000000000..869297cf7 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.action.yml @@ -0,0 +1,11 @@ +migrate_tools.add_group_action: + route_name: entity.migration_group.add_form + title: 'Add migration group' + appears_on: + - entity.migration_group.list + +#migrate_tools.add_migration_action: +# route_name: entity.migration.add_form +# title: 'Add migration' +# appears_on: +# - entity.migration.list diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.menu.yml b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.menu.yml new file mode 100644 index 000000000..d55ba56c1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.menu.yml @@ -0,0 +1,5 @@ +migrate_tools.menu: + title: Migrations + parent: system.admin_structure + description: Manage migration processes. + route_name: entity.migration_group.list diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.task.yml b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.task.yml new file mode 100644 index 000000000..415d1780a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.links.task.yml @@ -0,0 +1,41 @@ +# Component routing definition +entity.migration.overview: + route_name: entity.migration.overview + base_route: entity.migration.overview + title: View + +entity.migration.overview_general: + title: Overview + route_name: entity.migration.overview + parent_id: entity.migration.overview +entity.migration.overview_source: + title: Source + route_name: entity.migration.source + parent_id: entity.migration.overview + weight: 1 +entity.migration.overview_process: + title: Process + route_name: entity.migration.process + parent_id: entity.migration.overview + weight: 2 +entity.migration.overview_destination: + title: Destination + route_name: entity.migration.destination + parent_id: entity.migration.overview + weight: 3 + +entity.migration.edit_form: + route_name: entity.migration.edit_form + base_route: entity.migration.overview + title: Edit + +migrate_tools.messages: + route_name: migrate_tools.messages + base_route: entity.migration.overview + title: Messages + +entity.migration.delete_form: + route_name: entity.migration.delete_form + base_route: entity.migration.overview + title: Delete + weight: 10 diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.module b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.module new file mode 100644 index 000000000..bf1c8065c --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.module @@ -0,0 +1,29 @@ +set('admin_permission', 'administer migrations') + ->setHandlerClass('list_builder', 'Drupal\migrate_tools\Controller\MigrationListBuilder') + ->setFormClass('edit', 'Drupal\migrate_tools\Form\MigrationEditForm') + ->setFormClass('delete', 'Drupal\migrate_tools\Form\MigrationDeleteForm') + ->setLinkTemplate('list-form', '/admin/structure/migrate/manage/{migration_group}/migrations'); + + $entity_types['migration_group'] + ->set('admin_permission', 'administer migrations') + ->setHandlerClass('list_builder', 'Drupal\migrate_tools\Controller\MigrationGroupListBuilder') + ->setFormClass('add', 'Drupal\migrate_tools\Form\MigrationGroupAddForm') + ->setFormClass('edit', 'Drupal\migrate_tools\Form\MigrationGroupEditForm') + ->setFormClass('delete', 'Drupal\migrate_tools\Form\MigrationGroupDeleteForm') + ->setLinkTemplate('edit-form', '/admin/structure/migrate/manage/{migration_group}') + ->setLinkTemplate('delete-form', '/admin/structure/migrate/manage/{migration_group}/delete'); +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.permissions.yml b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.permissions.yml new file mode 100644 index 000000000..b5301e5c1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.permissions.yml @@ -0,0 +1,3 @@ +'administer migrations': + title: 'Administer migrations' + description: Create, edit, and manage migration processed. diff --git a/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.routing.yml b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.routing.yml new file mode 100644 index 000000000..edb4965c7 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/migrate_tools.routing.yml @@ -0,0 +1,124 @@ +# This is the router item for listing all migration group entities. +entity.migration_group.list: + path: '/admin/structure/migrate' + defaults: + _entity_list: 'migration_group' + _title: 'Migrations' + requirements: + _permission: 'administer migrations' + +# This is the router item for adding our migration group entity. +entity.migration_group.add_form: + path: '/admin/structure/migrate/add' + defaults: + _title: 'Add migration group' + _entity_form: migration_group.add + requirements: + _entity_create_access: migration_group + +# This is the router item for editing our migration group entity. +entity.migration_group.edit_form: + path: '/admin/structure/migrate/manage/{migration_group}' + defaults: + _title: 'Edit migration group' + _entity_form: migration_group.edit + requirements: + _entity_access: migration_group.update + +# This is the router item for deleting an instance of our migration group entity. +entity.migration_group.delete_form: + path: '/admin/structure/migrate/manage/{migration_group}/delete' + defaults: + _title: 'Delete migration group' + _entity_form: migration_group.delete + requirements: + _entity_access: migration_group.delete + +# This is the router item for listing all migration entities. +entity.migration.list: + path: '/admin/structure/migrate/manage/{migration_group}/migrations' + defaults: + _entity_list: 'migration' + _title: 'Migrations' + requirements: + _permission: 'administer migrations' + +# This is the router item for adding our migration entity. +#entity.migration.add_form: +# path: '/admin/structure/migrate/manage/{migration_group}/migrations/add' +# defaults: +# _title: 'Add migration' +# _entity_form: migration.add +# requirements: +# _entity_create_access: migration + +# This is the router item for viewing our migration entity. +entity.migration.overview: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}' + defaults: + _controller: '\Drupal\migrate_tools\Controller\MigrationController::overview' + _title: 'Migration overview' + requirements: + _permission: 'administer migrations' +entity.migration.source: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/source' + defaults: + _controller: '\Drupal\migrate_tools\Controller\MigrationController::source' + _title: 'Source' + requirements: + _permission: 'administer migrations' +entity.migration.process: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/process' + defaults: + _controller: '\Drupal\migrate_tools\Controller\MigrationController::process' + _title: 'Process' + requirements: + _permission: 'administer migrations' +entity.migration.process.run: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/process/run' + defaults: + _controller: '\Drupal\migrate_tools\Controller\MigrationController::run' + _title: 'Run' + requirements: + _permission: 'administer migrations' +entity.migration.destination: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/destination' + defaults: + _controller: '\Drupal\migrate_tools\Controller\MigrationController::destination' + _title: 'Destination' + requirements: + _permission: 'administer migrations' + +# This is the router item for editing our migration entity. +entity.migration.edit_form: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/edit' + defaults: + _title: 'Edit migration' + _entity_form: migration.edit + requirements: + _entity_access: migration.update + +# This is the router item for deleting an instance of our migration entity. +entity.migration.delete_form: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/delete' + defaults: + _title: 'Delete migration' + _entity_form: migration.delete + requirements: + _entity_access: migration.delete + +migrate_tools.messages: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/messages' + defaults: + _controller: '\Drupal\migrate_tools\Controller\MessageController::overview' + _title: 'Messages' + requirements: + _permission: 'administer migrations' + +migrate_tools.execute: + path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/execute' + defaults: + _form: '\Drupal\migrate_tools\Form\MigrationExecuteForm' + _title: 'Execute migration' + requirements: + _permission: 'administer migrations' diff --git a/sites/all/modules/contrib/migrate/migrate_tools/phpcs.xml b/sites/all/modules/contrib/migrate/migrate_tools/phpcs.xml new file mode 100644 index 000000000..1ccfe7eb4 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/phpcs.xml @@ -0,0 +1,126 @@ + + + PHP CodeSniffer configuration + . + + + + ./vendor/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Commands/MigrateToolsCommands.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Commands/MigrateToolsCommands.php new file mode 100644 index 000000000..501c6ac3b --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Commands/MigrateToolsCommands.php @@ -0,0 +1,741 @@ +migrationPluginManager = $migrationPluginManager; + $this->dateFormatter = $dateFormatter; + $this->entityTypeManager = $entityTypeManager; + $this->keyValue = $keyValue; + } + + /** + * List all migrations with current status. + * + * @param string $migration_names + * Restrict to a comma-separated list of migrations (Optional). + * @param array $options + * Additional options for the command. + * + * @command migrate:status + * + * @option group A comma-separated list of migration groups to list + * @option tag Name of the migration tag to list + * @option names-only Only return names, not all the details (faster) + * + * @usage migrate:status + * Retrieve status for all migrations + * @usage migrate:status --group=beer + * Retrieve status for all migrations in a given group + * @usage migrate:status --tag=user + * Retrieve status for all migrations with a given tag + * @usage migrate:status --group=beer --tag=user + * Retrieve status for all migrations in the beer group + * and with the user tag. + * @usage migrate:status beer_term,beer_node + * Retrieve status for specific migrations + * + * @validate-module-enabled migrate_tools + * + * @aliases ms, migrate-status + * + * @field-labels + * group: Group + * id: Migration ID + * status: Status + * total: Total + * imported: Imported + * unprocessed: Unprocessed + * last_imported: Last Imported + * @default-fields group,id,status,total,imported,unprocessed,last_imported + * + * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields + * Migrations status formatted as table. + */ + public function status( + $migration_names = '', + array $options = [ + 'group' => NULL, + 'tag' => NULL, + 'names-only' => NULL, + ] + ) { + $names_only = $options['names-only']; + + $migrations = $this->migrationsList($migration_names, $options); + + $table = []; + // Take it one group at a time, listing the migrations within each group. + foreach ($migrations as $group_id => $migration_list) { + /** @var \Drupal\migrate_plus\Entity\MigrationGroup $group */ + $group = $this->entityTypeManager->getStorage('migration_group')->load($group_id); + $group_name = !empty($group) ? "{$group->label()} ({$group->id()})" : $group_id; + + foreach ($migration_list as $migration_id => $migration) { + if ($names_only) { + $table[] = [ + 'group' => dt('Group: @name', ['@name' => $group_name]), + 'id' => $migration_id, + ]; + } + else { + try { + $map = $migration->getIdMap(); + $imported = $map->importedCount(); + $source_plugin = $migration->getSourcePlugin(); + } + catch (\Exception $e) { + $this->logger()->error( + dt( + 'Failure retrieving information on @migration: @message', + ['@migration' => $migration_id, '@message' => $e->getMessage()] + ) + ); + continue; + } + + try { + $source_rows = $source_plugin->count(); + // -1 indicates uncountable sources. + if ($source_rows == -1) { + $source_rows = dt('N/A'); + $unprocessed = dt('N/A'); + } + else { + $unprocessed = $source_rows - $map->processedCount(); + } + } + catch (\Exception $e) { + $this->logger()->error( + dt( + 'Could not retrieve source count from @migration: @message', + ['@migration' => $migration_id, '@message' => $e->getMessage()] + ) + ); + $source_rows = dt('N/A'); + $unprocessed = dt('N/A'); + } + + $status = $migration->getStatusLabel(); + $migrate_last_imported_store = $this->keyValue->get( + 'migrate_last_imported' + ); + $last_imported = $migrate_last_imported_store->get( + $migration->id(), + FALSE + ); + if ($last_imported) { + $last_imported = $this->dateFormatter->format( + $last_imported / 1000, + 'custom', + 'Y-m-d H:i:s' + ); + } + else { + $last_imported = ''; + } + $table[] = [ + 'group' => $group_name, + 'id' => $migration_id, + 'status' => $status, + 'total' => $source_rows, + 'imported' => $imported, + 'unprocessed' => $unprocessed, + 'last_imported' => $last_imported, + ]; + } + } + + // Add empty row to separate groups, for readability. + end($migrations); + if ($group_id !== key($migrations)) { + $table[] = []; + } + } + + return new RowsOfFields($table); + } + + /** + * Perform one or more migration processes. + * + * @param string $migration_names + * ID of migration(s) to import. Delimit multiple using commas. + * @param array $options + * Additional options for the command. + * + * @command migrate:import + * + * @option all Process all migrations. + * @option group A comma-separated list of migration groups to import + * @option tag Name of the migration tag to import + * @option limit Limit on the number of items to process in each migration + * @option feedback Frequency of progress messages, in items processed + * @option idlist Comma-separated list of IDs to import + * @option update In addition to processing unprocessed items from the + * source, update previously-imported items with the current data + * @option force Force an operation to run, even if all dependencies are not + * satisfied + * @option execute-dependencies Execute all dependent migrations first. + * + * @usage migrate:import --all + * Perform all migrations + * @usage migrate:import --group=beer + * Import all migrations in the beer group + * @usage migrate:import --tag=user + * Import all migrations with the user tag + * @usage migrate:import --group=beer --tag=user + * Import all migrations in the beer group and with the user tag + * @usage migrate:import beer_term,beer_node + * Import new terms and nodes + * @usage migrate:import beer_user --limit=2 + * Import no more than 2 users + * @usage migrate:import beer_user --idlist=5 + * Import the user record with source ID 5 + * + * @validate-module-enabled migrate_tools + * + * @aliases mim, migrate-import + * + * @throws \Exception + * If there are not enough parameters to the command. + */ + public function import( + $migration_names = '', + array $options = [ + 'all' => NULL, + 'group' => NULL, + 'tag' => NULL, + 'limit' => NULL, + 'feedback' => NULL, + 'idlist' => NULL, + 'update' => NULL, + 'force' => NULL, + 'execute-dependencies' => NULL, + ] + ) { + $group_names = $options['group']; + $tag_names = $options['tag']; + $all = $options['all']; + $additional_options = []; + if (!$all && !$group_names && !$migration_names && !$tag_names) { + throw new \Exception(dt('You must specify --all, --group, --tag or one or more migration names separated by commas')); + } + + foreach (['limit', 'feedback', 'idlist', 'update', 'force'] as $option) { + if ($options[$option]) { + $additional_options[$option] = $options[$option]; + } + } + + $migrations = $this->migrationsList($migration_names, $options); + if (empty($migrations)) { + $this->logger->error(dt('No migrations found.')); + } + + // Take it one group at a time, importing the migrations within each group. + foreach ($migrations as $group_id => $migration_list) { + array_walk( + $migration_list, + [$this, 'executeMigration'], + $additional_options + ); + } + } + + /** + * Rollback one or more migrations. + * + * @param string $migration_names + * Name of migration(s) to rollback. Delimit multiple using commas. + * @param array $options + * Additional options for the command. + * + * @command migrate:rollback + * + * @option all Process all migrations. + * @option group A comma-separated list of migration groups to rollback + * @option tag ID of the migration tag to rollback + * @option feedback Frequency of progress messages, in items processed + * + * @usage migrate:rollback --all + * Perform all migrations + * @usage migrate:rollback --group=beer + * Rollback all migrations in the beer group + * @usage migrate:rollback --tag=user + * Rollback all migrations with the user tag + * @usage migrate:rollback --group=beer --tag=user + * Rollback all migrations in the beer group and with the user tag + * @usage migrate:rollback beer_term,beer_node + * Rollback imported terms and nodes + * @validate-module-enabled migrate_tools + * + * @aliases mr, migrate-rollback + * + * @throws \Exception + * If there are not enough parameters to the command. + */ + public function rollback( + $migration_names = '', + array $options = [ + 'all' => NULL, + 'group' => NULL, + 'tag' => NULL, + 'feedback' => NULL, + ] + ) { + $group_names = $options['group']; + $tag_names = $options['tag']; + $all = $options['all']; + $additional_options = []; + if (!$all && !$group_names && !$migration_names && !$tag_names) { + throw new \Exception(dt('You must specify --all, --group, --tag, or one or more migration names separated by commas')); + } + + if ($options['feedback']) { + $additional_options['feedback'] = $options['feedback']; + } + + $migrations = $this->migrationsList($migration_names, $options); + if (empty($migrations)) { + $this->logger()->error(dt('No migrations found.')); + } + + // Take it one group at a time, + // rolling back the migrations within each group. + foreach ($migrations as $group_id => $migration_list) { + // Roll back in reverse order. + $migration_list = array_reverse($migration_list); + foreach ($migration_list as $migration_id => $migration) { + $executable = new MigrateExecutable( + $migration, + $this->getMigrateMessage(), + $additional_options + ); + // drush_op() provides --simulate support. + drush_op([$executable, 'rollback']); + } + } + } + + /** + * Stop an active migration operation. + * + * @param string $migration_id + * ID of migration to stop. + * + * @command migrate:stop + * + * @validate-module-enabled migrate_tools + * @aliases mst, migrate-stop + */ + public function stop($migration_id = '') { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance( + $migration_id + ); + if ($migration) { + $status = $migration->getStatus(); + switch ($status) { + case MigrationInterface::STATUS_IDLE: + $this->logger()->warning( + dt('Migration @id is idle', ['@id' => $migration_id]) + ); + break; + + case MigrationInterface::STATUS_DISABLED: + $this->logger()->warning( + dt('Migration @id is disabled', ['@id' => $migration_id]) + ); + break; + + case MigrationInterface::STATUS_STOPPING: + $this->logger()->warning( + dt('Migration @id is already stopping', ['@id' => $migration_id]) + ); + break; + + default: + $migration->interruptMigration(MigrationInterface::RESULT_STOPPED); + $this->logger()->notice( + dt('Migration @id requested to stop', ['@id' => $migration_id]) + ); + break; + } + } + else { + $this->logger()->error( + dt('Migration @id does not exist', ['@id' => $migration_id]) + ); + } + } + + /** + * Reset a active migration's status to idle. + * + * @param string $migration_id + * ID of migration to reset. + * + * @command migrate:reset-status + * + * @validate-module-enabled migrate_tools + * @aliases mrs, migrate-reset-status + */ + public function resetStatus($migration_id = '') { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance( + $migration_id + ); + if ($migration) { + $status = $migration->getStatus(); + if ($status == MigrationInterface::STATUS_IDLE) { + $this->logger()->warning( + dt('Migration @id is already Idle', ['@id' => $migration_id]) + ); + } + else { + $migration->setStatus(MigrationInterface::STATUS_IDLE); + $this->logger()->notice( + dt('Migration @id reset to Idle', ['@id' => $migration_id]) + ); + } + } + else { + $this->logger()->error( + dt('Migration @id does not exist', ['@id' => $migration_id]) + ); + } + } + + /** + * View any messages associated with a migration. + * + * @param string $migration_id + * ID of the migration. + * @param array $options + * Additional options for the command. + * + * @command migrate:messages + * + * @option csv Export messages as a CSV + * + * @usage migrate:messages MyNode + * Show all messages for the MyNode migration + * + * @validate-module-enabled migrate_tools + * + * @aliases mmsg,migrate-messages + */ + public function messages($migration_id, array $options = ['csv' => NULL]) { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance( + $migration_id + ); + if ($migration) { + $map = $migration->getIdMap(); + $first = TRUE; + $table = []; + foreach ($map->getMessageIterator() as $row) { + unset($row->msgid); + if ($first) { + // @todo: Ideally, replace sourceid* with source key names. Or, should + // getMessageIterator() do that? + foreach ($row as $column => $value) { + $table[0][] = $column; + } + $first = FALSE; + } + $table[] = (array) $row; + } + if (empty($table)) { + $this->logger()->notice(dt('No messages for this migration')); + } + else { + if ($options['csv']) { + foreach ($table as $row) { + fputcsv(STDOUT, $row); + } + } + else { + $widths = []; + foreach ($table[0] as $header) { + $widths[] = strlen($header) + 1; + } + + drush_print_table($table); + } + } + } + else { + $this->logger()->error( + dt('Migration @id does not exist', ['@id' => $migration_id]) + ); + } + } + + /** + * List the fields available for mapping in a source. + * + * @param string $migration_id + * ID of the migration. + * + * @command migrate:fields-source + * + * @usage migrate:fields-source my_node + * List fields for the source in the my_node migration + * + * @validate-module-enabled migrate_tools + * + * @aliases mfs, migrate-fields-source + */ + public function fieldsSource($migration_id) { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance( + $migration_id + ); + if ($migration) { + $source = $migration->getSourcePlugin(); + $table = []; + foreach ($source->fields() as $machine_name => $description) { + $table[] = [strip_tags($description), $machine_name]; + } + drush_print_table($table); + } + else { + $this->logger()->error( + dt('Migration @id does not exist', ['@id' => $migration_id]) + ); + } + } + + /** + * Retrieve a list of active migrations. + * + * @param string $migration_ids + * Comma-separated list of migrations - + * if present, return only these migrations. + * @param array $options + * Command options. + * + * @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. + */ + protected function migrationsList($migration_ids = '', array $options = []) { + // Filter keys must match the migration configuration property name. + $filter['migration_group'] = $options['group'] ? explode( + ',', + $options['group'] + ) : []; + $filter['migration_tags'] = $options['tag'] ? explode( + ',', + $options['tag'] + ) : []; + + $manager = $this->migrationPluginManager; + $plugins = $manager->createInstances([]); + $matched_migrations = []; + + // Get the set of migrations that may be filtered. + if (empty($migration_ids)) { + $matched_migrations = $plugins; + } + else { + // Get the requested migrations. + $migration_ids = explode(',', Unicode::strtolower($migration_ids)); + foreach ($plugins as $id => $migration) { + if (in_array(Unicode::strtolower($id), $migration_ids)) { + $matched_migrations[$id] = $migration; + } + } + } + + // Do not return any migrations which fail to meet requirements. + /** @var \Drupal\migrate\Plugin\Migration $migration */ + foreach ($matched_migrations as $id => $migration) { + if ($migration->getSourcePlugin() instanceof RequirementsInterface) { + try { + $migration->getSourcePlugin()->checkRequirements(); + } + catch (RequirementsException $e) { + unset($matched_migrations[$id]); + } + } + } + + // Filters the matched migrations if a group or a tag has been input. + if (!empty($filter['migration_group']) || !empty($filter['migration_tags'])) { + // Get migrations in any of the specified groups and with any of the + // specified tags. + foreach ($filter as $property => $values) { + if (!empty($values)) { + $filtered_migrations = []; + foreach ($values as $search_value) { + foreach ($matched_migrations as $id => $migration) { + // Cast to array because migration_tags can be an array. + $configured_values = (array) $migration->get($property); + $configured_id = (in_array( + $search_value, + $configured_values + )) ? $search_value : 'default'; + if (empty($search_value) || $search_value == $configured_id) { + if (empty($migration_ids) || in_array( + Unicode::strtolower($id), + $migration_ids + )) { + $filtered_migrations[$id] = $migration; + } + } + } + } + $matched_migrations = $filtered_migrations; + } + } + } + + // Sort the matched migrations by group. + if (!empty($matched_migrations)) { + foreach ($matched_migrations as $id => $migration) { + $configured_group_id = empty($migration->get('migration_group')) ? 'default' : $migration->get('migration_group'); + $migrations[$configured_group_id][$id] = $migration; + } + } + return isset($migrations) ? $migrations : []; + } + + /** + * Executes a single migration. + * + * If the --execute-dependencies option was given, + * the migration's dependencies will also be executed first. + * + * @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 + * Additional options of the command. + * + * @throws \Exception + * If some migrations failed during execution. + */ + protected function executeMigration( + MigrationInterface $migration, + $migration_id, + array $options = [] + ) { + if (isset($options['execute-dependencies'])) { + if ($required_IDS = $migration->get('requirements')) { + $manager = $this->migrationPluginManager; + $required_migrations = $manager->createInstances($required_IDS); + $dependency_options = array_merge($options, ['is_dependency' => TRUE]); + array_walk($required_migrations, __FUNCTION__, $dependency_options); + } + } + if (!empty($options['force'])) { + $migration->set('requirements', []); + } + if (!empty($options['update'])) { + $migration->getIdMap()->prepareUpdate(); + } + $executable = new MigrateExecutable($migration, $this->getMigrateMessage(), $options); + // drush_op() provides --simulate support. + drush_op([$executable, 'import']); + if ($count = $executable->getFailedCount()) { + // Nudge Drush to use a non-zero exit code. + throw new \Exception( + dt( + '!name Migration - !count failed.', + ['!name' => $migration_id, '!count' => $count] + ) + ); + } + } + + /** + * Gets the migrate message logger. + * + * @return \Drupal\migrate\MigrateMessageInterface + * The migrate message service. + */ + protected function getMigrateMessage() { + if (!isset($this->migrateMessage)) { + $this->migrateMessage = new Drush9LogMigrateMessage($this->logger()); + } + return $this->migrateMessage; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MessageController.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MessageController.php new file mode 100644 index 000000000..abf921b19 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MessageController.php @@ -0,0 +1,144 @@ +get('database'), + $container->get('plugin.manager.migration') + ); + } + + /** + * Constructs a MessageController object. + * + * @param \Drupal\Core\Database\Connection $database + * A database connection. + * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager + * The migration plugin manager. + */ + public function __construct(Connection $database, MigrationPluginManagerInterface $migration_plugin_manager) { + $this->database = $database; + $this->migrationPluginManager = $migration_plugin_manager; + } + + /** + * Gets an array of log level classes. + * + * @return array + * An array of log level classes. + */ + public static function getLogLevelClassMap() { + return [ + MigrationInterface::MESSAGE_INFORMATIONAL => 'migrate-message-4', + MigrationInterface::MESSAGE_NOTICE => 'migrate-message-3', + MigrationInterface::MESSAGE_WARNING => 'migrate-message-2', + MigrationInterface::MESSAGE_ERROR => 'migrate-message-1', + ]; + } + + /** + * Displays a listing of migration messages. + * + * Messages are truncated at 56 chars. + * + * @param string $migration_group + * Machine name of the migration's group. + * + * @param string $migration + * Machine name of the migration. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function overview($migration_group, $migration) { + $rows = []; + $classes = static::getLogLevelClassMap(); + /** @var MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration); + $source_id_field_names = array_keys($migration->getSourcePlugin()->getIds()); + $column_number = 1; + foreach ($source_id_field_names as $source_id_field_name) { + $header[] = [ + 'data' => $source_id_field_name, + 'field' => 'sourceid' . $column_number++, + 'class' => [RESPONSIVE_PRIORITY_MEDIUM], + ]; + } + $header[] = [ + 'data' => $this->t('Severity level'), + 'field' => 'level', + 'class' => [RESPONSIVE_PRIORITY_LOW], + ]; + $header[] = [ + 'data' => $this->t('Message'), + 'field' => 'message', + ]; + + $message_table = $migration->getIdMap()->messageTableName(); + $map_table = $migration->getIdMap()->mapTableName(); + $query = $this->database->select($message_table, 'msg') + ->extend('\Drupal\Core\Database\Query\PagerSelectExtender') + ->extend('\Drupal\Core\Database\Query\TableSortExtender'); + $query->innerJoin($map_table, 'map', 'msg.source_ids_hash=map.source_ids_hash'); + $query->fields('msg'); + $query->fields('map'); + $result = $query + ->limit(50) + ->orderByHeader($header) + ->execute(); + + foreach ($result as $message_row) { + $column_number = 1; + foreach ($source_id_field_names as $source_id_field_name) { + $column_name = 'sourceid' . $column_number++; + $row[$column_name] = $message_row->$column_name; + } + $row['level'] = $message_row->level; + $row['message'] = $message_row->message; + $row['class'] = [Html::getClass('migrate-message-' . $message_row->level), $classes[$message_row->level]]; + $rows[] = $row; + } + + $build['message_table'] = [ + '#type' => 'table', + '#header' => $header, + '#rows' => $rows, + '#attributes' => ['id' => $message_table, 'class' => [$message_table]], + '#empty' => $this->t('No messages for this migration.'), + ]; + $build['message_pager'] = ['#type' => 'pager']; + + return $build; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationController.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationController.php new file mode 100644 index 000000000..6004c3edb --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationController.php @@ -0,0 +1,311 @@ +migrationPluginManager = $migration_plugin_manager; + $this->currentRouteMatch = $currentRouteMatch; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.migration'), + $container->get('current_route_match') + ); + } + + /** + * Displays an overview of a migration entity. + * + * @param string $migration_group + * Machine name of the migration's group. + * @param string $migration + * Machine name of the migration. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function overview($migration_group, $migration) { + + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration); + + $build['overview'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Overview'), + ]; + + $build['overview']['group'] = [ + '#title' => $this->t('Group:'), + '#markup' => Xss::filterAdmin($migration_group), + '#type' => 'item', + ]; + + $build['overview']['description'] = [ + '#title' => $this->t('Description:'), + '#markup' => Xss::filterAdmin($migration->label()), + '#type' => 'item', + ]; + + $migration_dependencies = $migration->getMigrationDependencies(); + if (!empty($migration_dependencies['required'])) { + $build['overview']['dependencies'] = [ + '#title' => $this->t('Migration Dependencies') , + '#markup' => Xss::filterAdmin(implode(', ', $migration_dependencies['required'])), + '#type' => 'item', + ]; + } + if (!empty($migration_dependencies['optional'])) { + $build['overview']['soft_dependencies'] = [ + '#title' => $this->t('Soft Migration Dependencies'), + '#markup' => Xss::filterAdmin(implode(', ', $migration_dependencies['optional'])), + '#type' => 'item', + ]; + } + + return $build; + } + + /** + * Display source information of a migration entity. + * + * @param string $migration_group + * Machine name of the migration's group. + * @param string $migration + * Machine name of the migration. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function source($migration_group, $migration) { + + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration); + + // Source field information. + $build['source'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Source'), + '#group' => 'detail', + '#description' => $this->t('

These are the fields available from the source of this migration task. The machine names listed here may be used as sources in the process pipeline.

'), + '#attributes' => [ + 'id' => 'migration-detail-source', + ], + ]; + + $source = $migration->getSourcePlugin(); + $build['source']['query'] = [ + '#type' => 'item', + '#title' => $this->t('Query'), + '#markup' => '
' . Xss::filterAdmin($source) . '
', + ]; + $header = [$this->t('Machine name'), $this->t('Description')]; + $rows = []; + foreach ($source->fields($migration) as $machine_name => $description) { + $rows[] = [ + ['data' => Html::escape($machine_name)], + ['data' => Xss::filterAdmin($description)], + ]; + } + + $build['source']['fields'] = [ + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + '#empty' => $this->t('No fields'), + ]; + + return $build; + } + + /** + * Run a migration. + * + * @param string $migration_group + * Machine name of the migration's group. + * @param string $migration + * Machine name of the migration. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function run($migration_group, $migration) { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration); + + $migrateMessage = new MigrateMessage(); + $options = []; + + $executable = new MigrateBatchExecutable($migration, $migrateMessage, $options); + $executable->batchImport(); + + $migration_group = $this->currentRouteMatch->getParameter('migration_group'); + $route_parameters = [ + 'migration_group' => $migration_group, + 'migration' => $migration->id(), + ]; + return batch_process(Url::fromRoute('entity.migration.process', $route_parameters)); + } + + /** + * Display process information of a migration entity. + * + * @param string $migration_group + * Machine name of the migration's group. + * @param string $migration + * Machine name of the migration. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function process($migration_group, $migration) { + + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration); + + // Process information. + $build['process'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Process'), + ]; + + $header = [ + $this->t('Destination'), + $this->t('Source'), + $this->t('Process plugin'), + $this->t('Default'), + ]; + $rows = []; + foreach ($migration->getProcess() as $destination_id => $process_line) { + $row = []; + $row[] = ['data' => Html::escape($destination_id)]; + if (isset($process_line[0]['source'])) { + $row[] = ['data' => Xss::filterAdmin($process_line[0]['source'])]; + } + else { + $row[] = ''; + } + if (isset($process_line[0]['plugin'])) { + $row[] = ['data' => Xss::filterAdmin($process_line[0]['plugin'])]; + } + else { + $row[] = ''; + } + if (isset($process_line[0]['default_value'])) { + $row[] = ['data' => Xss::filterAdmin($process_line[0]['default_value'])]; + } + else { + $row[] = ''; + } + $rows[] = $row; + } + + $build['process']['fields'] = [ + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + '#empty' => $this->t('No process defined.'), + ]; + + $build['process']['run'] = [ + '#type' => 'link', + '#title' => $this->t('Run'), + '#url' => Url::fromRoute('entity.migration.process.run', ['migration_group' => $migration_group, 'migration' => $migration->id()]), + ]; + + return $build; + } + + /** + * Displays destination information of a migration entity. + * + * @param string $migration_group + * Machine name of the migration's group. + * @param string $migration + * Machine name of the migration. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function destination($migration_group, $migration) { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration); + + // Destination field information. + $build['destination'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Destination'), + '#group' => 'detail', + '#description' => $this->t('

These are the fields available in the destination plugin of this migration task. The machine names are those available to be used as the keys in the process pipeline.

'), + '#attributes' => [ + 'id' => 'migration-detail-destination', + ], + ]; + $destination = $migration->getDestinationPlugin(); + $build['destination']['type'] = [ + '#type' => 'item', + '#title' => $this->t('Type'), + '#markup' => Xss::filterAdmin($destination->getPluginId()), + ]; + $header = [$this->t('Machine name'), $this->t('Description')]; + $rows = []; + $destination_fields = $destination->fields() ?: []; + foreach ($destination_fields as $machine_name => $description) { + $rows[] = [ + ['data' => Html::escape($machine_name)], + ['data' => Xss::filterAdmin($description)], + ]; + } + + $build['destination']['fields'] = [ + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + '#empty' => $this->t('No fields'), + ]; + + return $build; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationGroupListBuilder.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationGroupListBuilder.php new file mode 100644 index 000000000..6757c22b1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationGroupListBuilder.php @@ -0,0 +1,68 @@ +t('Migration Group'); + $header['machine_name'] = $this->t('Machine Name'); + $header['description'] = $this->t('Description'); + $header['source_type'] = $this->t('Source Type'); + return $header + parent::buildHeader(); + } + + /** + * Builds a row for an entity in the entity listing. + * + * @param EntityInterface $entity + * The entity for which to build the row. + * + * @return array + * A render array of the table row for displaying the entity. + * + * @see Drupal\Core\Entity\EntityListController::render() + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $entity->label(); + $row['machine_name'] = $entity->id(); + $row['description'] = $entity->get('description'); + $row['source_type'] = $entity->get('source_type'); + + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOperations(EntityInterface $entity) { + $operations = parent::getDefaultOperations($entity); + $operations['list'] = [ + 'title' => $this->t('List migrations'), + 'weight' => 0, + 'url' => Url::fromRoute('entity.migration.list', ['migration_group' => $entity->id()]), + ]; + + return $operations; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationListBuilder.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationListBuilder.php new file mode 100644 index 000000000..b14fc45f0 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Controller/MigrationListBuilder.php @@ -0,0 +1,228 @@ +currentRouteMatch = $current_route_match; + $this->migrationPluginManager = $migration_plugin_manager; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorage($entity_type->id()), + $container->get('current_route_match'), + $container->get('plugin.manager.migration') + ); + } + + /** + * Retrieve the migrations belonging to the appropriate group. + * + * @return array + * An array of entity IDs. + */ + protected function getEntityIds() { + $migration_group = $this->currentRouteMatch->getParameter('migration_group'); + + $query = $this->getStorage()->getQuery() + ->sort($this->entityType->getKey('id')); + + $migration_groups = MigrationGroup::loadMultiple(); + + if (array_key_exists($migration_group, $migration_groups)) { + $query->condition('migration_group', $migration_group); + } + else { + $query->notExists('migration_group'); + } + // Only add the pager if a limit is specified. + if ($this->limit) { + $query->pager($this->limit); + } + return $query->execute(); + } + + /** + * Builds the header row for the entity listing. + * + * @return array + * A render array structure of header strings. + * + * @see \Drupal\Core\Entity\EntityListController::render() + */ + public function buildHeader() { + $header['label'] = $this->t('Migration'); + $header['machine_name'] = $this->t('Machine Name'); + $header['status'] = $this->t('Status'); + $header['total'] = $this->t('Total'); + $header['imported'] = $this->t('Imported'); + $header['unprocessed'] = $this->t('Unprocessed'); + $header['messages'] = $this->t('Messages'); + $header['last_imported'] = $this->t('Last Imported'); + $header['operations'] = $this->t('Operations'); + return $header; + } + + /** + * Builds a row for a migration plugin. + * + * @param \Drupal\Core\Entity\EntityInterface $migration_entity + * The migration plugin for which to build the row. + * + * @return array + * A render array of the table row for displaying the plugin information. + * + * @see \Drupal\Core\Entity\EntityListController::render() + */ + public function buildRow(EntityInterface $migration_entity) { + try { + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration_entity->id()); + $migration_group = $migration->get('migration_group'); + if (!$migration_group) { + $migration_group = 'default'; + } + $route_parameters = [ + 'migration_group' => $migration_group, + 'migration' => $migration->id(), + ]; + $row['label'] = [ + 'data' => [ + '#type' => 'link', + '#title' => $migration->label(), + '#url' => Url::fromRoute("entity.migration.overview", $route_parameters), + ], + ]; + $row['machine_name'] = $migration->id(); + $row['status'] = $migration->getStatusLabel(); + } catch (PluginException $e) { + return NULL; + } + + try { + // Derive the stats. + $source_plugin = $migration->getSourcePlugin(); + $row['total'] = $source_plugin->count(); + $map = $migration->getIdMap(); + $row['imported'] = $map->importedCount(); + // -1 indicates uncountable sources. + if ($row['total'] == -1) { + $row['total'] = $this->t('N/A'); + $row['unprocessed'] = $this->t('N/A'); + } + else { + $row['unprocessed'] = $row['total'] - $map->processedCount(); + } + $row['messages'] = [ + 'data' => [ + '#type' => 'link', + '#title' => $map->messageCount(), + '#url' => Url::fromRoute("migrate_tools.messages", $route_parameters), + ], + ]; + $migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported'); + $last_imported = $migrate_last_imported_store->get($migration->id(), FALSE); + if ($last_imported) { + /** @var \Drupal\Core\Datetime\DateFormatter $date_formatter */ + $date_formatter = \Drupal::service('date.formatter'); + $row['last_imported'] = $date_formatter->format($last_imported / 1000, + 'custom', 'Y-m-d H:i:s'); + } + else { + $row['last_imported'] = ''; + } + + $row['operations']['data'] = [ + '#type' => 'dropbutton', + '#links' => [ + 'simple_form' => [ + 'title' => $this->t('Execute'), + 'url' => Url::fromRoute('migrate_tools.execute', [ + 'migration_group' => $migration_group, + 'migration' => $migration->id(), + ]), + ], + ], + ]; + } catch (PluginException $e) { + // Derive the stats. + $row['status'] = $this->t('No data found'); + $row['total'] = $this->t('N/A'); + $row['imported'] = $this->t('N/A'); + $row['unprocessed'] = $this->t('N/A'); + $row['messages'] = $this->t('N/A'); + $row['last_imported'] = $this->t('N/A'); + $row['operations'] = $this->t('N/A'); + } + + return $row; + } + + /** + * @param \Drupal\Core\Url $url + * The URL associated with an operation. + * + * @param $migration_group + * The migration's parent group. + */ + protected function addGroupParameter(Url $url, $migration_group) { + if (!$migration_group) { + $migration_group = 'default'; + } + $route_parameters = $url->getRouteParameters() + ['migration_group' => $migration_group]; + $url->setRouteParameters($route_parameters); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Drush9LogMigrateMessage.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Drush9LogMigrateMessage.php new file mode 100644 index 000000000..0217a58e1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Drush9LogMigrateMessage.php @@ -0,0 +1,48 @@ + 'notice', + ]; + + /** + * DrushLogMigrateMessage constructor. + */ + public function __construct(LoggerInterface $logger) { + $this->setLogger($logger); + } + + /** + * Output a message from the migration. + * + * @param string $message + * The message to display. + * @param string $type + * The type of message to display. + */ + public function display($message, $type = 'status') { + $type = isset($this->map[$type]) ? $this->map[$type] : $type; + $this->logger->log($type, $message); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/DrushLogMigrateMessage.php b/sites/all/modules/contrib/migrate/migrate_tools/src/DrushLogMigrateMessage.php new file mode 100644 index 000000000..9ed1d9fb0 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/DrushLogMigrateMessage.php @@ -0,0 +1,23 @@ +t('Are you sure you want to delete migration %label?', [ + '%label' => $this->entity->label(), + ]); + } + + /** + * Gather the confirmation text. + * + * @return string + * Translated string. + */ + public function getConfirmText() { + return $this->t('Delete Migration'); + } + + /** + * Gets the cancel URL. + * + * @return \Drupal\Core\Url + * The URL to go to if the user cancels the deletion. + */ + public function getCancelUrl() { + return new Url('entity.migration_group.list'); + } + + /** + * The submit handler for the confirm form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Delete the entity. + $this->entity->delete(); + + // Set a message that the entity was deleted. + drupal_set_message(t('Migration %label was deleted.', [ + '%label' => $this->entity->label(), + ])); + + // Redirect the user to the list controller when complete. + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationEditForm.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationEditForm.php new file mode 100644 index 000000000..ad9ba8c7a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationEditForm.php @@ -0,0 +1,51 @@ +getRouteParameters() + ['migration_group' => $migration_group]; + $url->setRouteParameters($route_parameters); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationExecuteForm.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationExecuteForm.php new file mode 100644 index 000000000..9bfd8fbdc --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationExecuteForm.php @@ -0,0 +1,231 @@ +migrationPluginManager = $migration_plugin_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.migration') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'migration_execute_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + + $form = []; + + $form['operations'] = $this->migrateMigrateOperations(); + + return $form; + } + + + /** + * Get Operations. + */ + private function migrateMigrateOperations() { + // Build the 'Update options' form. + $form = [ + '#type' => 'fieldset', + '#title' => t('Operations'), + ]; + $options = [ + 'import' => t('Import'), + 'rollback' => t('Rollback'), + 'stop' => t('Stop'), + 'reset' => t('Reset'), + ]; + $form['operation'] = [ + '#type' => 'select', + '#title' => t('Choose an operation to run'), + '#options' => $options, + '#default_value' => 'import', + '#required' => TRUE, + ]; + $form['submit'] = [ + '#type' => 'submit', + '#value' => t('Execute'), + ]; + $definitions = []; + $definitions[] = $this->t('Import: Imports all previously unprocessed records from the source, plus any records marked for update, into destination Drupal objects.'); + $definitions[] = $this->t('Rollback: Deletes all Drupal objects created by the import.'); + $definitions[] = $this->t('Stop: Cleanly interrupts any import or rollback processes that may currently be running.'); + $definitions[] = $this->t('Reset: Sometimes a process may fail to stop cleanly, and be left stuck in an Importing or Rolling Back status. Choose Reset to clear the status and permit other operations to proceed.'); + $form['definitions'] = [ + '#theme' => 'item_list', + '#title' => $this->t('Definitions'), + '#list_type' => 'ul', + '#items' => $definitions, + ]; + + $form['options'] = [ + '#type' => 'fieldset', + '#title' => t('Options'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ]; + $form['options']['update'] = [ + '#type' => 'checkbox', + '#title' => t('Update'), + '#description' => t('Check this box to update all previously-imported content + in addition to importing new content. Leave unchecked to only import + new content'), + ]; + $form['options']['force'] = [ + '#type' => 'checkbox', + '#title' => t('Ignore dependencies'), + '#description' => t('Check this box to ignore dependencies when running imports + - all tasks will run whether or not their dependent tasks have + completed.'), + ]; + // @TODO: Limit is not working. Perhaps because of batch? See + // https://www.drupal.org/project/migrate_tools/issues/2924298 +// $form['options']['limit'] = [ +// '#type' => 'textfield', +// '#title' => t('Limit to:'), +// '#size' => 10, +// '#description' => t('Set a limit of how many items to process for each migration task.'), +// ]; + return $form; + } + + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + if (empty($form_state->getValue('operation'))) { + $form_state->setErrorByName('operation', $this->t('Please select an operation.')); + return; + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + + $operation = $form_state->getValue('operation'); + + if ($form_state->getValue('limit')) { + $limit = $form_state->getValue('limit'); + } + else { + $limit = 0; + } + + if ($form_state->getValue('update')) { + $update = $form_state->getValue('update'); + } + else { + $update = 0; + } + if ($form_state->getValue('force')) { + $force = $form_state->getValue('force'); + } + else { + $force = 0; + } + + $migration_name = \Drupal::routeMatch()->getParameter('migration'); + + if ($migration_name) { + + /** @var MigrationInterface $migration */ + $migration = $this->migrationPluginManager->createInstance($migration_name); + $migrateMessage = new MigrateMessage(); + + switch ($operation) { + case 'import': + + $options = [ + 'limit' => $limit, + 'update' => $update, + 'force' => $force, + ]; + + $executable = new MigrateBatchExecutable($migration, $migrateMessage, $options); + $executable->batchImport(); + + break; + + case 'rollback': + + $options = [ + 'limit' => $limit, + 'update' => $update, + 'force' => $force + ]; + + $executable = new MigrateBatchExecutable($migration, $migrateMessage, $options); + $executable->rollback(); + + break; + + case 'stop': + + $migration->interruptMigration(MigrationInterface::RESULT_STOPPED); + + break; + + case 'reset': + + $migration->setStatus(MigrationInterface::STATUS_IDLE); + + break; + + } + } + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationFormBase.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationFormBase.php new file mode 100644 index 000000000..cf2c8cee7 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationFormBase.php @@ -0,0 +1,194 @@ +entityQueryFactory = $query_factory; + } + + /** + * Factory method for MigrationFormBase. + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * A container interface service. + * + * @return \Drupal\migrate_tools\Form\MigrationGroupFormBase + */ + public static function create(ContainerInterface $container) { + return new static($container->get('entity.query')); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::form(). + * + * Builds the entity add/edit form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An associative array containing the migration add/edit form. + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // Get anything we need from the base class. + $form = parent::buildForm($form, $form_state); + + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ + $migration = $this->entity; + + $form['warning'] = [ + '#markup' => $this->t('Creating migrations is not yet supported. See :url', [ + ':url' => 'https://www.drupal.org/node/2573241', + ]) + ]; + + // Build the form. + $form['label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $migration->label(), + '#required' => TRUE, + ]; + $form['id'] = [ + '#type' => 'machine_name', + '#title' => $this->t('Machine name'), + '#default_value' => $migration->id(), + '#machine_name' => [ + 'exists' => [$this, 'exists'], + 'replace_pattern' => '([^a-z0-9_]+)|(^custom$)', + 'error' => 'The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".', + ], + '#disabled' => !$migration->isNew(), + ]; + + $groups = MigrationGroup::loadMultiple(); + $group_options = []; + foreach ($groups as $group) { + $group_options[$group->id()] = $group->label(); + } + if (!$migration->get('migration_group') && isset($group_options['default'])) { + $migration->set('migration_group', 'default'); + } + + $form['migration_group'] = [ + '#type' => 'select', + '#title' => $this->t('Migration Group'), + '#empty_value' => '', + '#default_value' => $migration->get('migration_group'), + '#options' => $group_options, + '#description' => $this->t('Assign this migration to an existing group.'), + ]; + + return $form; + } + + /** + * Checks for an existing migration group. + * + * @param string|int $entity_id + * The entity ID. + * @param array $element + * The form element. + * @param FormStateInterface $form_state + * The form state. + * + * @return bool + * TRUE if this format already exists, FALSE otherwise. + */ + public function exists($entity_id, array $element, FormStateInterface $form_state) { + // Use the query factory to build a new migration entity query. + $query = $this->entityQueryFactory->get('migration'); + + // Query the entity ID to see if its in use. + $result = $query->condition('id', $element['#field_prefix'] . $entity_id) + ->execute(); + + // We don't need to return the ID, only if it exists or not. + return (bool) $result; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::actions(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) { + // Get the basic actins from the base class. + $actions = parent::actions($form, $form_state); + + // Change the submit button text. + $actions['submit']['#value'] = $this->t('Save'); + + // Return the result. + return $actions; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return $this + */ + public function save(array $form, FormStateInterface $form_state) { + $migration = $this->getEntity(); + $status = $migration->save(); + + if ($status == SAVED_UPDATED) { + // If we edited an existing entity... + drupal_set_message($this->t('Migration %label has been updated.', ['%label' => $migration->label()])); + } + else { + // If we created a new entity... + drupal_set_message($this->t('Migration %label has been added.', ['%label' => $migration->label()])); + } + + // Redirect the user back to the listing route after the save operation. + $form_state->setRedirect('entity.migration.list', + ['migration_group' => $migration->get('migration_group')]); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupAddForm.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupAddForm.php new file mode 100644 index 000000000..3efbf8c88 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupAddForm.php @@ -0,0 +1,37 @@ +t('Create Migration Group'); + return $actions; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupDeleteForm.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupDeleteForm.php new file mode 100644 index 000000000..a126856bf --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupDeleteForm.php @@ -0,0 +1,71 @@ +t('Are you sure you want to delete migration group %label?', [ + '%label' => $this->entity->label(), + ]); + } + + /** + * Gather the confirmation text. + * + * @return string + * Translated string. + */ + public function getConfirmText() { + return $this->t('Delete Migration Group'); + } + + /** + * Gets the cancel URL. + * + * @return \Drupal\Core\Url + * The URL to go to if the user cancels the deletion. + */ + public function getCancelUrl() { + return new Url('entity.migration_group.list'); + } + + /** + * The submit handler for the confirm form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Delete the entity. + $this->entity->delete(); + + // Set a message that the entity was deleted. + drupal_set_message(t('Migration group %label was deleted.', [ + '%label' => $this->entity->label(), + ])); + + // Redirect the user to the list controller when complete. + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupEditForm.php b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupEditForm.php new file mode 100644 index 000000000..ee52359cd --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/Form/MigrationGroupEditForm.php @@ -0,0 +1,37 @@ +entityQueryFactory = $query_factory; + } + + /** + * Factory method for MigrationGroupFormBase. + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * A container interface service. + * + * @return \Drupal\migrate_tools\Form\MigrationFormBase + */ + public static function create(ContainerInterface $container) { + return new static($container->get('entity.query')); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::form(). + * + * Builds the entity add/edit form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An associative array containing the migration group add/edit form. + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // Get anything we need from the base class. + $form = parent::buildForm($form, $form_state); + + /** @var \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group */ + $migration_group = $this->entity; + + // Build the form. + $form['label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $migration_group->label(), + '#required' => TRUE, + ]; + $form['id'] = [ + '#type' => 'machine_name', + '#title' => $this->t('Machine name'), + '#default_value' => $migration_group->id(), + '#machine_name' => [ + 'exists' => [$this, 'exists'], + 'replace_pattern' => '([^a-z0-9_]+)|(^custom$)', + 'error' => 'The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".', + ], + '#disabled' => !$migration_group->isNew(), + ]; + $form['description'] = [ + '#type' => 'textfield', + '#title' => $this->t('Description'), + '#maxlength' => 255, + '#default_value' => $migration_group->get('description'), + ]; + $form['source_type'] = [ + '#type' => 'textfield', + '#title' => $this->t('Source type'), + '#description' => $this->t('Type of source system the group is migrating from, for example "Drupal 6" or "WordPress 4".'), + '#maxlength' => 255, + '#default_value' => $migration_group->get('source_type'), + ]; + + // Return the form. + return $form; + } + + /** + * Checks for an existing migration group. + * + * @param string|int $entity_id + * The entity ID. + * @param array $element + * The form element. + * @param FormStateInterface $form_state + * The form state. + * + * @return bool + * TRUE if this format already exists, FALSE otherwise. + */ + public function exists($entity_id, array $element, FormStateInterface $form_state) { + // Use the query factory to build a new migration group entity query. + $query = $this->entityQueryFactory->get('migration_group'); + + // Query the entity ID to see if its in use. + $result = $query->condition('id', $element['#field_prefix'] . $entity_id) + ->execute(); + + // We don't need to return the ID, only if it exists or not. + return (bool) $result; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::actions(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) { + // Get the basic actins from the base class. + $actions = parent::actions($form, $form_state); + + // Change the submit button text. + $actions['submit']['#value'] = $this->t('Save'); + + // Return the result. + return $actions; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return $this + */ + public function save(array $form, FormStateInterface $form_state) { + $migration_group = $this->getEntity(); + $status = $migration_group->save(); + + if ($status == SAVED_UPDATED) { + // If we edited an existing entity... + drupal_set_message($this->t('Migration group %label has been updated.', ['%label' => $migration_group->label()])); + } + else { + // If we created a new entity... + drupal_set_message($this->t('Migration group %label has been added.', ['%label' => $migration_group->label()])); + } + + // Redirect the user back to the listing route after the save operation. + $form_state->setRedirect('entity.migration_group.list'); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/MigrateBatchExecutable.php b/sites/all/modules/contrib/migrate/migrate_tools/src/MigrateBatchExecutable.php new file mode 100644 index 000000000..d1aa35e1a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/MigrateBatchExecutable.php @@ -0,0 +1,290 @@ +updateExistingRows = $options['update']; + } + + if (isset($options['force'])) { + $this->checkDependencies = $options['force']; + } + + parent::__construct($migration, $message, $options); + $this->migrationPluginManager = \Drupal::getContainer()->get('plugin.manager.migration'); + } + + /** + * Sets the current batch content so listeners can update the messages. + * + * @param array $context + */ + public function setBatchContext(&$context) { + $this->batchContext = &$context; + } + + /** + * Gets a reference to the current batch context. + * + * @return array + */ + public function &getBatchContext() { + return $this->batchContext; + } + + /** + * Setup batch operations for running the migration. + */ + public function batchImport() { + // Create the batch operations for each migration that needs to be executed. + // This includes the migration for this executable, but also the dependent + // migrations. + $operations = $this->batchOperations([$this->migration], 'import', [ + 'limit' => $this->itemLimit, + 'update' => $this->updateExistingRows, + 'force' => $this->checkDependencies + ]); + + if (count($operations) > 0) { + $batch = [ + 'operations' => $operations, + 'title' => t('Migrating %migrate', ['%migrate' => $this->migration->label()]), + 'init_message' => t('Start migrating %migrate', ['%migrate' => $this->migration->label()]), + 'progress_message' => t('Migrating %migrate', ['%migrate' => $this->migration->label()]), + 'error_message' => t('An error occurred while migrating %migrate.', ['%migrate' => $this->migration->label()]), + 'finished' => '\Drupal\migrate_tools\MigrateBatchExecutable::batchFinishedImport', + ]; + + batch_set($batch); + } + } + + /** + * Helper to generate the batch operations for importing migrations. + * + * @param array $migrations + * @param array $operation + * @param array $options + * + * @return array + */ + protected function batchOperations($migrations, $operation, $options = []) { + + $operations = []; + + /** + * @var string $id + * @var Migration $migration + */ + foreach ($migrations as $id => $migration) { + + if (!empty($options['update'])) { + $migration->getIdMap()->prepareUpdate(); + } + + if (!empty($options['force'])) { + $migration->set('requirements', []); + } + else { + $dependencies = $migration->getMigrationDependencies(); + if (!empty($dependencies['required'])) { + $required_migrations = $this->migrationPluginManager->createInstances($dependencies['required']); + // For dependent migrations will need to be migrate all items. + $dependent_options = $options; + $dependent_options['limit'] = 0; + $operations += $this->batchOperations($required_migrations, $operation, [ + 'limit' => 0, + 'update' => $options['update'], + 'force' => $options['force'] + ]); + } + } + + $operations[] = [ + '\Drupal\migrate_tools\MigrateBatchExecutable::batchProcessImport', + [$migration->id(), $options] + ]; + } + + return $operations; + } + + /** + * Batch 'operation' callback + * + * @param string $migration_id + * @param array $options + * @param array $context + * + */ + static public function batchProcessImport($migration_id, $options, &$context) { + + if (empty($context['sandbox'])) { + $context['finished'] = 0; + $context['sandbox'] = []; + $context['sandbox']['total'] = 0; + $context['sandbox']['counter'] = 0; + $context['sandbox']['batch_limit'] = 0; + $context['sandbox']['operation'] = MigrateBatchExecutable::BATCH_IMPORT; + } + + // Prepare the migration executable. + $message = new MigrateMessage(); + /** @var MigrationInterface $migration */ + $migration = \Drupal::getContainer()->get('plugin.manager.migration')->createInstance($migration_id); + $executable = new MigrateBatchExecutable($migration, $message, $options); + + if (empty($context['sandbox']['total'])) { + $context['sandbox']['total'] = $executable->getSource()->count(); + $context['sandbox']['batch_limit'] = $executable->calculateBatchLimit($context); + $context['results'][$migration->id()] = [ + '@numitems' => 0, + '@created' => 0, + '@updated' => 0, + '@failures' => 0, + '@ignored' => 0, + '@name' => $migration->id() + ]; + } + + // Every iteration, we reset out batch counter. + $context['sandbox']['batch_counter'] = 0; + + // Make sure we know our batch context. + $executable->setBatchContext($context); + + // Do the import. + $result = $executable->import(); + + // Store the result, we will need to combine the results of all our iterations. + $context['results'][$migration->id()] = [ + '@numitems' => $context['results'][$migration->id()]['@numitems'] + $executable->getProcessedCount(), + '@created' => $context['results'][$migration->id()]['@created'] + $executable->getCreatedCount(), + '@updated' => $context['results'][$migration->id()]['@updated'] + $executable->getUpdatedCount(), + '@failures' => $context['results'][$migration->id()]['@failures'] + $executable->getFailedCount(), + '@ignored' => $context['results'][$migration->id()]['@ignored'] + $executable->getIgnoredCount(), + '@name' => $migration->id() + ]; + + // Do some housekeeping. + if ( + $result != MigrationInterface::RESULT_INCOMPLETE + ) { + $context['finished'] = 1; + } + else { + $context['sandbox']['counter'] = $context['results'][$migration->id()]['@numitems']; + if ($context['sandbox']['counter'] <= $context['sandbox']['total']) { + $context['finished'] = ((float) $context['sandbox']['counter'] / (float) $context['sandbox']['total']); + $context['message'] = t('Importing %migration (@percent%).', [ + '%migration' => $migration->label(), + '@percent' => (int) ($context['finished'] * 100) + ]); + } + } + + } + + /** + * Finished callback for import batches. + * + * @param $success + * @param $results + * @param $operations + * @param $elapsed + */ + static public function batchFinishedImport($success, $results, $operations, $elapsed) { + if ($success) { + foreach ($results as $migration_id => $result) { + $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'"; + $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'"; + drupal_set_message(\Drupal::translation()->formatPlural($result['@numitems'], + $singular_message, + $plural_message, + $result)); + } + } + } + + /** + * @inheritdoc + */ + public function checkStatus() { + $status = parent::checkStatus(); + + if ($status == MigrationInterface::RESULT_COMPLETED) { + // Do some batch housekeeping. + $context = $this->getBatchContext(); + + if (!empty($context['sandbox']) && $context['sandbox']['operation'] == MigrateBatchExecutable::BATCH_IMPORT) { + $context['sandbox']['batch_counter']++; + if ($context['sandbox']['batch_counter'] >= $context['sandbox']['batch_limit']) { + $status = MigrationInterface::RESULT_INCOMPLETE; + } + } + } + + return $status; + } + + /** + * Calculates how much a single batch iteration will handle. + * + * @param $context + * + * @return float + */ + public function calculateBatchLimit($context) { + // TODO Maybe we need some other more sophisticated logic here? + return ceil($context['sandbox']['total'] / 100); + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/src/MigrateExecutable.php b/sites/all/modules/contrib/migrate/migrate_tools/src/MigrateExecutable.php new file mode 100644 index 000000000..01dba4234 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/src/MigrateExecutable.php @@ -0,0 +1,366 @@ + 0, + MigrateIdMapInterface::STATUS_IGNORED => 0, + MigrateIdMapInterface::STATUS_IMPORTED => 0, + MigrateIdMapInterface::STATUS_NEEDS_UPDATE => 0, + ]; + + /** + * Counter of map deletions. + * + * @var int + */ + protected $deleteCounter = 0; + + /** + * Maximum number of items to process in this migration. 0 indicates no limit + * is to be applied. + * + * @var int + */ + protected $itemLimit = 0; + + /** + * Frequency (in items) at which progress messages should be emitted. + * + * @var int + */ + protected $feedback = 0; + + /** + * List of specific source IDs to import. + * + * @var array + */ + protected $idlist = []; + + /** + * Count of number of items processed so far in this migration. + * @var int + */ + protected $counter = 0; + + /** + * Whether the destination item exists before saving. + * + * @var bool + */ + protected $preExistingItem = FALSE; + + /** + * List of event listeners we have registered. + * + * @var array + */ + protected $listeners = []; + + /** + * {@inheritdoc} + */ + public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, array $options = []) { + parent::__construct($migration, $message); + if (isset($options['limit'])) { + $this->itemLimit = $options['limit']; + } + if (isset($options['feedback'])) { + $this->feedback = $options['feedback']; + } + if (isset($options['idlist'])) { + if (is_string($options['idlist'])) { + $this->idlist = explode(',', $options['idlist']); + array_walk($this->idlist, function (&$value, $key) { + $value = explode(':', $value); + }); + } + } + + $this->listeners[MigrateEvents::MAP_SAVE] = [$this, 'onMapSave']; + $this->listeners[MigrateEvents::MAP_DELETE] = [$this, 'onMapDelete']; + $this->listeners[MigrateEvents::POST_IMPORT] = [$this, 'onPostImport']; + $this->listeners[MigrateEvents::POST_ROLLBACK] = [$this, 'onPostRollback']; + $this->listeners[MigrateEvents::PRE_ROW_SAVE] = [$this, 'onPreRowSave']; + $this->listeners[MigrateEvents::POST_ROW_DELETE] = [$this, 'onPostRowDelete']; + $this->listeners[MigratePlusEvents::PREPARE_ROW] = [$this, 'onPrepareRow']; + foreach ($this->listeners as $event => $listener) { + \Drupal::service('event_dispatcher')->addListener($event, $listener); + } + } + + /** + * Count up any map save events. + * + * @param \Drupal\migrate\Event\MigrateMapSaveEvent $event + * The map event. + */ + public function onMapSave(MigrateMapSaveEvent $event) { + // Only count saves for this migration. + if ($event->getMap()->getQualifiedMapTableName() == $this->migration->getIdMap()->getQualifiedMapTableName()) { + $fields = $event->getFields(); + // Distinguish between creation and update. + if ($fields['source_row_status'] == MigrateIdMapInterface::STATUS_IMPORTED && + $this->preExistingItem + ) { + $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]++; + } + else { + $this->saveCounters[$fields['source_row_status']]++; + } + } + } + + /** + * Count up any rollback events. + * + * @param \Drupal\migrate\Event\MigrateMapDeleteEvent $event + * The map event. + */ + public function onMapDelete(MigrateMapDeleteEvent $event) { + $this->deleteCounter++; + } + + /** + * Return the number of items created. + * + * @return int + */ + public function getCreatedCount() { + return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED]; + } + + /** + * Return the number of items updated. + * + * @return int + */ + public function getUpdatedCount() { + return $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]; + } + + /** + * Return the number of items ignored. + * + * @return int + */ + public function getIgnoredCount() { + return $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED]; + } + + /** + * Return the number of items that failed. + * + * @return int + */ + public function getFailedCount() { + return $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED]; + } + + /** + * Return the total number of items processed. Note that STATUS_NEEDS_UPDATE + * is not counted, since this is typically set on stubs created as side + * effects, not on the primary item being imported. + * + * @return int + */ + public function getProcessedCount() { + return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED] + + $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE] + + $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED] + + $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED]; + } + + /** + * Return the number of items rolled back. + * + * @return int + */ + public function getRollbackCount() { + return $this->deleteCounter; + } + + /** + * Reset all the per-status counters to 0. + */ + protected function resetCounters() { + foreach ($this->saveCounters as $status => $count) { + $this->saveCounters[$status] = 0; + } + $this->deleteCounter = 0; + } + + /** + * React to migration completion. + * + * @param \Drupal\migrate\Event\MigrateImportEvent $event + * The map event. + */ + public function onPostImport(MigrateImportEvent $event) { + $migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported'); + $migrate_last_imported_store->set($event->getMigration()->id(), round(microtime(TRUE) * 1000)); + $this->progressMessage(); + $this->removeListeners(); + } + + /** + * Clean up all our event listeners. + */ + protected function removeListeners() { + foreach ($this->listeners as $event => $listener) { + \Drupal::service('event_dispatcher')->removeListener($event, $listener); + } + } + + /** + * Emit information on what we've done since the last feedback (or the + * beginning of this migration). + * + * @param bool $done + */ + protected function progressMessage($done = TRUE) { + $processed = $this->getProcessedCount(); + if ($done) { + $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'"; + $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'"; + } + else { + $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'"; + $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'"; + } + $this->message->display(\Drupal::translation()->formatPlural($processed, + $singular_message, $plural_message, + ['@numitems' => $processed, + '@created' => $this->getCreatedCount(), + '@updated' => $this->getUpdatedCount(), + '@failures' => $this->getFailedCount(), + '@ignored' => $this->getIgnoredCount(), + '@name' => $this->migration->id()])); + } + + /** + * React to rollback completion. + * + * @param \Drupal\migrate\Event\MigrateRollbackEvent $event + * The map event. + */ + public function onPostRollback(MigrateRollbackEvent $event) { + $this->rollbackMessage(); + $this->removeListeners(); + } + + /** + * Emit information on what we've done since the last feedback (or the + * beginning of this migration). + * + * @param bool $done + */ + protected function rollbackMessage($done = TRUE) { + $rolled_back = $this->getRollbackCount(); + if ($done) { + $singular_message = "Rolled back 1 item - done with '@name'"; + $plural_message = "Rolled back @numitems items - done with '@name'"; + } + else { + $singular_message = "Rolled back 1 item - continuing with '@name'"; + $plural_message = "Rolled back @numitems items - continuing with '@name'"; + } + $this->message->display(\Drupal::translation()->formatPlural($rolled_back, + $singular_message, $plural_message, + ['@numitems' => $rolled_back, + '@name' => $this->migration->id()])); + } + + /** + * React to an item about to be imported. + * + * @param \Drupal\migrate\Event\MigratePreRowSaveEvent $event + * The pre-save event. + */ + public function onPreRowSave(MigratePreRowSaveEvent $event) { + $id_map = $event->getRow()->getIdMap(); + if (!empty($id_map['destid1'])) { + $this->preExistingItem = TRUE; + } + else { + $this->preExistingItem = FALSE; + } + } + + /** + * React to item rollback. + * + * @param \Drupal\migrate\Event\MigrateRowDeleteEvent $event + * The post-save event. + */ + public function onPostRowDelete(MigrateRowDeleteEvent $event) { + if ($this->feedback && ($this->deleteCounter) && $this->deleteCounter % $this->feedback == 0) { + $this->rollbackMessage(FALSE); + $this->resetCounters(); + } + } + + /** + * React to a new row. + * + * @param \Drupal\migrate_plus\Event\MigratePrepareRowEvent $event + * The prepare-row event. + * + * @throws \Drupal\migrate\MigrateSkipRowException + */ + public function onPrepareRow(MigratePrepareRowEvent $event) { + if (!empty($this->idlist)) { + $row = $event->getRow(); + /** + * @TODO replace for $source_id = $row->getSourceIdValues(); when https://www.drupal.org/node/2698023 is fixed + */ + $migration = $event->getMigration(); + $source_id = array_merge(array_flip(array_keys($migration->getSourcePlugin() + ->getIds())), $row->getSourceIdValues()); + $skip = TRUE; + foreach ($this->idlist as $item) { + if (array_values($source_id) == $item) { + $skip = FALSE; + break; + } + } + if ($skip) { + throw new MigrateSkipRowException(NULL, FALSE); + } + } + if ($this->feedback && ($this->counter) && $this->counter % $this->feedback == 0) { + $this->progressMessage(FALSE); + $this->resetCounters(); + } + $this->counter++; + if ($this->itemLimit && ($this->getProcessedCount() + 1) >= $this->itemLimit) { + $event->getMigration()->interruptMigration(MigrationInterface::RESULT_COMPLETED); + } + + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration.fruit_terms.yml b/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration.fruit_terms.yml new file mode 100755 index 000000000..7f606d127 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration.fruit_terms.yml @@ -0,0 +1,32 @@ +langcode: en +status: true +dependencies: { } +id: fruit_terms +label: Fruit Terms +class: null +field_plugin_method: null +cck_plugin_method: null +migration_tags: { } +migration_group: default +source: + plugin: embedded_data + data_rows: + - + name: Apple + - + name: Banana + - + name: Orange + ids: + name: + type: string + constants: + vocabulary: fruit +process: + name: name + vid: constants/vocabulary +destination: + plugin: entity:taxonomy_term +migration_dependencies: + required: { } + optional: { } diff --git a/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration_group.default.yml b/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration_group.default.yml new file mode 100644 index 000000000..0f35a2189 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/config/install/migrate_plus.migration_group.default.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: { } +id: default +label: Default +description: '' +source_type: '' +module: null +shared_configuration: null diff --git a/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/migrate_tools_test.info.yml b/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/migrate_tools_test.info.yml new file mode 100644 index 000000000..83bff424b --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/tests/modules/migrate_tools_test/migrate_tools_test.info.yml @@ -0,0 +1,14 @@ +type: module +name: Migrate Tools Test +description: 'Test module to test Migrate Tools.' +package: Testing +# core: 8.x +dependencies: + - drupal:migrate (>=8.3) + - migrate_plus:migrate_plus + +# Information added by Drupal.org packaging script on 2017-11-17 +version: '8.x-4.0-beta1+5-dev' +core: '8.x' +project: 'migrate_tools' +datestamp: 1510918687 diff --git a/sites/all/modules/contrib/migrate/migrate_tools/tests/src/Functional/MigrateExecutionFormTest.php b/sites/all/modules/contrib/migrate/migrate_tools/tests/src/Functional/MigrateExecutionFormTest.php new file mode 100644 index 000000000..76bb7caca --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_tools/tests/src/Functional/MigrateExecutionFormTest.php @@ -0,0 +1,132 @@ +vocabulary = $this->createVocabulary(['vid' => 'fruit', 'name' => 'Fruit']); + $this->vocabularyQuery = $this->container->get('entity_type.manager') + ->getStorage('taxonomy_term') + ->getQuery(); + // Log in as user 1. Migrations in the UI can only be performed as user 1. + $this->drupalLogin($this->rootUser); + } + + /** + * Tests execution of import and rollback of a migration. + * + * @throws \Behat\Mink\Exception\ExpectationException + */ + public function testExecution() { + $group = 'default'; + $migration = 'fruit_terms'; + $urlPath = "/admin/structure/migrate/manage/{$group}/migrations/{$migration}/execute"; + $real_count = $this->vocabularyQuery->count()->execute(); + $expected_count = 0; + $this->assertEquals($expected_count, $real_count); + $this->drupalGet($urlPath); + $this->assertSession()->responseContains('Choose an operation to run'); + $edit = [ + 'operation' => 'import', + ]; + $this->drupalPostForm($urlPath, $edit, t('Execute')); + $real_count = $this->vocabularyQuery->count()->execute(); + $expected_count = 3; + $this->assertEquals($expected_count, $real_count); + $edit = [ + 'operation' => 'rollback', + ]; + $this->drupalPostForm($urlPath, $edit, t('Execute')); + $real_count = $this->vocabularyQuery->count()->execute(); + $expected_count = 0; + $this->assertEquals($expected_count, $real_count); + $edit = [ + 'operation' => 'import', + ]; + $this->drupalPostForm($urlPath, $edit, t('Execute')); + $real_count = $this->vocabularyQuery->count()->execute(); + $expected_count = 3; + $this->assertEquals($expected_count, $real_count); + } + + /** + * Creates a custom vocabulary based on default settings. + * + * @param array $values + * An array of settings to change from the defaults. + * Example: 'vid' => 'foo'. + * + * @return \Drupal\taxonomy\VocabularyInterface + * Created vocabulary. + */ + protected function createVocabulary(array $values = []) { + // Find a non-existent random vocabulary name. + if (!isset($values['vid'])) { + do { + $id = strtolower($this->randomMachineName(8)); + } while (Vocabulary::load($id)); + } + else { + $id = $values['vid']; + } + $values += [ + 'id' => $id, + 'name' => $id, + ]; + $vocabulary = Vocabulary::create($values); + $status = $vocabulary->save(); + + $this->assertSame($status, SAVED_NEW); + + return $vocabulary; + } + +} diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/LICENSE.txt b/sites/all/modules/contrib/migrate/migrate_upgrade/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/README.txt b/sites/all/modules/contrib/migrate/migrate_upgrade/README.txt new file mode 100644 index 000000000..cf5ee51cf --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/README.txt @@ -0,0 +1,87 @@ +The migrate_upgrade module provides drush support for performing upgrades from +previous versions of Drupal to Drupal 8. It implements two drush commands: + +* migrate-upgrade - performs a complete import of the source site's configuration +and content into the target Drupal 8 site. Optionally, with the --configure-only +flag, it may create migration configurations for such an import without actually +running them, to permit customization of the import process. + +* migrate-upgrade-rollback - removes content and certain configuration +previously imported either by the migrate-upgrade command or by the core +upgrade UI. + +migrate-upgrade +=============== +The upgrade command requires a Drupal 6-style database URL of the source site's +database, and the location of the source site's public files. + +drush migrate-upgrade --legacy-db-url=mysql://user:pw@127.0.0.1/d6db --legacy-root=http://example.com + +The --legacy-root option may be either the domain of your existing Drupal site +(with the public files pulled by HTTP), or a local file directory into which you +have copied the files directory from your source site. + +If your source site used a database prefix for all tables, you may specify the +prefix with --legacy-db-prefix. Migration from sites with partial or mixed +prefixing is not supported. Note that if the source site is stored in a Postgres +schema, you must set the prefix to the schema with a period appended (e.g., +--legacy-db-prefix=drupal.). + +The migrate-upgrade command, like the core upgrade UI, is designed to be run on +a freshly installed and empty Drupal 8 site (where the only site configuration +that has been done is enabling any modules for which you wish to migrate data). + +migrate-upgrade-rollback +======================== + +The rollback command has no arguments or options: + +drush migrate-upgrade-rollback + +If it detects that an upgrade has been performed, either by migrate-upgrade or +by the core UI, it removes all content imported via the migration process (it +identifies the upgrade by the presence of the migrate_drupal_ui.performed state +key). In addition, any configuration entites created by the migration process +(such as content type and field definitions) are also removed. Because simple +configuration settings (such as the site title) are generally modified rather +than created by the upgrade process, and the original values are not preserved, +those changes are not rolled back. To completely return to the previous state, +you need to restore the site from backup, or reinstall a fresh empty site. + +migrate-upgrade --configure-only +================================ +At the time of this release, tools have not yet been developed (along the lines +of the migrate_d2d_ui module under Drupal 7) for customizing Drupal-to-Drupal +migrations in Drupal 8. For now, the best option short of doing custom +development is to use the --configure-only option on migrate-upgrade to replace +the actual execution of the migrations with export of their configuration to +configuration entities, which can then be modified as needed for a particular +migration scenario. A suggested workflow: + +1. Install a fresh empty D8 site, enabling all modules for which you wish to + migrate data. +2. Run the drush migrate-upgrade command with the --configure-only option. This + generates migration configuration entities in the D8 database (config table). +3. Create a custom module containing only a .info.yml file (with dependencies on + migrate_plus and migrate_drupal) and a config/install directory. +4. Export your site configuration, e.g. drush cex --destination=/tmp/export +5. Copy the migration configuration that was generated by migrate-upgrade into + the custom module - be sure *not* to copy the default group configuration, + which is defined by migrate_plus: + cp /tmp/export/migrate_plus.migration.* /tmp/export/migrate_plus.migration_group.migrate_*.yml migrate_custom/config/install/ +6. Look at that migrate_plus.migration_group.* file - you'll see your database + configuration captured there. In most cases, what you'll want to do is define + your database connection in settings.php with those credentials under the key + that is configured there - you won't want to commit the credentials to your + git repo. +7. Edit the generated .yml files to reflect your custom migration path. +8. Reinstall D8, enable your custom module and migrate_tools, and proceed to + work with your Drupal migrations as you would with any custom migration. + Hint: you'll probably want config_devel so you can edit .yml files in + config/install and immediately test your changes. + +Note that the configuration entities generated above need to be prefixed to +avoid conflict with the core migration plugins they originated from. For +example, by default the core d6_user plugin generates the upgrade_d6_user +configuration entity. You may modify the 'upgrade_' prefix by providing a +--migration-prefix option. diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/composer.json b/sites/all/modules/contrib/migrate/migrate_upgrade/composer.json new file mode 100644 index 000000000..cb5dd87ec --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/composer.json @@ -0,0 +1,11 @@ +{ + "name": "drupal/migrate_upgrade", + "description": "Drush support for direct upgrades from older Drupal versions.", + "type": "drupal-module", + "require-dev": { + "drupal/coder": "^8" + }, + "license": "GPL-2.0+", + "require": {}, + "minimum-stability": "dev" +} diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.drush.inc b/sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.drush.inc new file mode 100644 index 000000000..ef5404d31 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.drush.inc @@ -0,0 +1,93 @@ + 'Perform one or more upgrade processes.', + 'options' => [ + 'legacy-db-url' => 'A Drupal 6 style database URL. Required if you do not set legacy-db-key.', + 'legacy-db-key' => 'A database connection key from settings.php. Use as an alternative to legacy-db-url', + 'legacy-db-prefix' => 'Prefix of the legacy Drupal installation.', + 'legacy-root' => 'Site address or root of the legacy Drupal installation', + 'configure-only' => 'Set up the appropriate upgrade processes but do not perform them', + 'migration-prefix' => 'With configure-only, a prefix to apply to generated migration ids. Defaults to \'upgrade_\'', + ], + 'examples' => [ + 'migrate-upgrade --legacy-db-url=\'mysql://root:pass@127.0.0.1/d6\'' => 'Upgrade a Drupal 6 database to Drupal 8', + 'migrate-upgrade --legacy-db-key=\'drupal_7\'' => 'Upgrade Drupal 7 database where the connection to Drupal 7 has already been created in settings.php ($databases[\'drupal_7\'])', + 'migrate-upgrade --legacy-db-url=\'mysql://root:pass@127.0.0.1/d7\' --configure-only --migration-prefix=d7_custom_' => 'Generate migrations for a custom migration from Drupal 7 to Drupal 8', + ], + 'drupal dependencies' => ['migrate_upgrade'], + ]; + $items['migrate-upgrade-rollback'] = [ + 'description' => 'Rolls back and removes upgrade migrations.', + 'examples' => [ + 'migrate-upgrade-rollback' => 'Rolls back a previously-run upgrade', + ], + 'drupal dependencies' => ['migrate_upgrade'], + ]; + + return $items; +} + +/** + * Execute the upgrade command, configuring the necessary migrations and + * optionally perform the imports. + */ +function drush_migrate_upgrade() { + $runner = new MigrateUpgradeDrushRunner(); + + try { + $runner->configure(); + if (drush_get_option('configure-only')) { + $runner->export(); + } + else { + $runner->import(); + \Drupal::state()->set('migrate_drupal_ui.performed', REQUEST_TIME); + } + // Remove the global database state. + \Drupal::state()->delete('migrate.fallback_state_key'); + } + catch (\Exception $e) { + drush_log($e->getMessage(), 'error'); + } +} + +/** + * Rolls back any upgrade migrations that are present, and deletes the migrations + * themselves. + */ +function drush_migrate_upgrade_rollback() { + if ($date_performed = \Drupal::state()->get('migrate_drupal_ui.performed')) { + if (drush_confirm(dt('All migrations tagged as \'Drupal\' will be rolled back. Are you sure?'))) { + $runner = new MigrateUpgradeDrushRunner(); + + try { + drush_log(dt('Rolling back the upgrades performed @date', + ['@date' => \Drupal::service('date.formatter')->format($date_performed)])); + $runner->rollback(); + \Drupal::state()->delete('migrate_drupal_ui.performed'); + drush_log(dt('Rolled back upgrades')); + } + catch (\Exception $e) { + drush_log($e->getMessage(), 'error'); + } + } + else { + drush_user_abort(); + } + } + else { + drush_log(dt('No upgrade operation has been performed.'), 'warning'); + } +} diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.info.yml b/sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.info.yml new file mode 100644 index 000000000..822bd9c7a --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/migrate_upgrade.info.yml @@ -0,0 +1,16 @@ +name: Drupal Upgrade +type: module +description: 'Drush support for direct upgrades from older Drupal versions.' +package: Migration +# core: 8.x +dependencies: + - drupal:migrate (>=8.2) + - drupal:migrate_drupal + - migrate_plus:migrate_plus + - drupal:dblog + +# Information added by Drupal.org packaging script on 2017-09-02 +version: '8.x-3.0-rc2' +core: '8.x' +project: 'migrate_upgrade' +datestamp: 1504384149 diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/phpcs.xml b/sites/all/modules/contrib/migrate/migrate_upgrade/phpcs.xml new file mode 100644 index 000000000..1ccfe7eb4 --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/phpcs.xml @@ -0,0 +1,126 @@ + + + PHP CodeSniffer configuration + . + + + + ./vendor/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sites/all/modules/contrib/migrate/migrate_upgrade/src/DrushLogMigrateMessage.php b/sites/all/modules/contrib/migrate/migrate_upgrade/src/DrushLogMigrateMessage.php new file mode 100644 index 000000000..888fafd3d --- /dev/null +++ b/sites/all/modules/contrib/migrate/migrate_upgrade/src/DrushLogMigrateMessage.php @@ -0,0 +1,23 @@ +version = $this->getLegacyDrupalVersion($connection); + $database_state['key'] = drush_get_option('legacy-db-key'); + $database_state_key = 'migrate_drupal_' . $this->version; + \Drupal::state()->set($database_state_key, $database_state); + \Drupal::state()->set('migrate.fallback_state_key', $database_state_key); + } + else { + $db_url = drush_get_option('legacy-db-url'); + $db_spec = drush_convert_db_from_db_url($db_url); + $db_prefix = drush_get_option('legacy-db-prefix'); + $db_spec['prefix'] = $db_prefix; + $connection = $this->getConnection($db_spec); + $this->version = $this->getLegacyDrupalVersion($connection); + $this->createDatabaseStateSettings($db_spec, $this->version); + } + + $this->databaseStateKey = 'migrate_drupal_' . $this->version; + $migrations = $this->getMigrations($this->databaseStateKey, $this->version); + $this->migrationList = []; + foreach ($migrations as $migration) { + $this->applyFilePath($migration); + $this->expandNodeMigrations($migration); + $this->migrationList[$migration->id()] = $migration; + } + } + + /** + * Adds the source base path configuration to relevant migrations. + * + * @param \Drupal\migrate\Plugin\MigrationInterface $migration + * Migration to alter with the provided path. + */ + protected function applyFilePath(MigrationInterface $migration) { + $destination = $migration->getDestinationConfiguration(); + if ($destination['plugin'] === 'entity:file') { + // Make sure we have a single trailing slash. + $source_base_path = rtrim(drush_get_option('legacy-root'), '/') . '/'; + $source = $migration->getSourceConfiguration(); + $source['constants']['source_base_path'] = $source_base_path; + $migration->set('source', $source); + } + } + + /** + * For D6 term_node migrations, make sure the nid reference is expanded. + * + * @param \Drupal\migrate\Plugin\MigrationInterface $migration + * Migration to alter with the list of node migrations. + */ + protected function expandNodeMigrations(MigrationInterface $migration) { + $source = $migration->getSourceConfiguration(); + // Track the node migrations as we see them. + if ($source['plugin'] == 'd6_node') { + $this->nodeMigrations[] = $migration->id(); + } + elseif ($source['plugin'] == 'd6_term_node' || $source['plugin'] == 'd6_term_node_revision') { + if ($source['plugin'] == 'd6_term_node') { + $id_property = 'nid'; + } + else { + $id_property = 'vid'; + } + // If the ID mapping is to the underived d6_node migration, replace + // it with an expanded list of node migrations. + $process = $migration->getProcess(); + $new_nid_process = []; + foreach ($process[$id_property] as $delta => $plugin_configuration) { + if (in_array($plugin_configuration['plugin'], $this->migrationLookupPluginIds) && + is_string($plugin_configuration['migration']) && + substr($plugin_configuration['migration'], -7) == 'd6_node') { + $plugin_configuration['migration'] = $this->nodeMigrations; + } + $new_nid_process[$delta] = $plugin_configuration; + } + $migration->setProcessOfProperty($id_property, $new_nid_process); + } + } + + /** + * Run the configured migrations. + */ + public function import() { + static::$messages = new DrushLogMigrateMessage(); + if (drush_get_option('debug')) { + \Drupal::service('event_dispatcher')->addListener(MigrateEvents::IDMAP_MESSAGE, + [get_class(), 'onIdMapMessage']); + } + foreach ($this->migrationList as $migration_id => $migration) { + drush_print(dt('Upgrading @migration', ['@migration' => $migration_id])); + $executable = new MigrateExecutable($migration, static::$messages); + // drush_op() provides --simulate support. + drush_op([$executable, 'import']); + } + } + + /** + * Export the configured migration plugins as configuration entities. + */ + public function export() { + $db_info = \Drupal::state()->get($this->databaseStateKey); + + // Create a group to hold the database configuration. + $group = [ + 'id' => $this->databaseStateKey, + 'label' => 'Import from Drupal ' . $this->version, + 'description' => 'Migrations originally generated from drush migrate-upgrade --configure-only', + 'source_type' => 'Drupal ' . $this->version, + 'shared_configuration' => [ + 'source' => [ + 'key' => 'drupal_' . $this->version, + ] + ] + ]; + + // Only add the database connection info to the configuration entity + // if it was passed in as a parameter. + if (!empty(drush_get_option('legacy-db-url'))) { + $group['shared_configuration']['source']['database'] = $db_info['database']; + } + + // Ditto for the key. + if (!empty(drush_get_option('legacy-db-key'))) { + $group['shared_configuration']['source']['key'] = drush_get_option('legacy-db-key'); + } + + $group = MigrationGroup::create($group); + $group->save(); + foreach ($this->migrationList as $migration_id => $migration) { + drush_print(dt('Exporting @migration as @new_migration', + ['@migration' => $migration_id, '@new_migration' => $this->modifyId($migration_id)])); + $entity_array['id'] = $migration_id; + $entity_array['class'] = $migration->get('class'); + $entity_array['cck_plugin_method'] = $migration->get('cck_plugin_method'); + $entity_array['migration_group'] = $this->databaseStateKey; + $entity_array['migration_tags'] = $migration->get('migration_tags'); + $entity_array['label'] = $migration->get('label'); + $entity_array['source'] = $migration->getSourceConfiguration(); + $entity_array['destination'] = $migration->getDestinationConfiguration(); + $entity_array['process'] = $migration->get('process'); + $entity_array['migration_dependencies'] = $migration->getMigrationDependencies(); + $migration_entity = Migration::create($this->substituteIds($entity_array)); + $migration_entity->save(); + } + } + + /** + * Rewrite any migration plugin IDs so they won't conflict with the core + * IDs. + * + * @param $entity_array + * A configuration array for a migration. + * + * @return array + * The migration configuration array modified with new IDs. + */ + protected function substituteIds($entity_array) { + $entity_array['id'] = $this->modifyId($entity_array['id']); + foreach ($entity_array['migration_dependencies'] as $type => $dependencies) { + foreach ($dependencies as $key => $dependency) { + $entity_array['migration_dependencies'][$type][$key] = $this->modifyId($dependency); + } + } + $this->substituteMigrationIds($entity_array['process']); + return $entity_array; + } + + /** + * Recursively substitute IDs for migration plugins. + * + * @param mixed $process + */ + protected function substituteMigrationIds(&$process) { + if (is_array($process)) { + // We found a migration plugin, change the ID. + if (isset($process['plugin']) && in_array($process['plugin'], $this->migrationLookupPluginIds)) { + if (is_array($process['migration'])) { + $new_migration = []; + foreach ($process['migration'] as $migration) { + $new_migration[] = $this->modifyId($migration); + } + $process['migration'] = $new_migration; + } + else { + $process['migration'] = $this->modifyId($process['migration']); + } + } + else { + // Recurse on each array member. + foreach ($process as &$subprocess) { + $this->substituteMigrationIds($subprocess); + } + } + } + } + + /** + * @param $id + * The original core plugin ID. + * + * @return string + * The ID modified to serve as a configuration entity ID. + */ + protected function modifyId($id) { + return drush_get_option('migration-prefix', 'upgrade_') . str_replace(':', '_', $id); + } + + /** + * Rolls back the configured migrations. + */ + public function rollback() { + static::$messages = new DrushLogMigrateMessage(); + $database_state_key = \Drupal::state()->get('migrate.fallback_state_key'); + $database_state = \Drupal::state()->get($database_state_key); + $db_spec = $database_state['database']; + $connection = $this->getConnection($db_spec); + $version = $this->getLegacyDrupalVersion($connection); + $migrations = $this->getMigrations('migrate_drupal_' . $version, $version); + + // Roll back in reverse order. + $this->migrationList = array_reverse($migrations); + + foreach ($migrations as $migration) { + drush_print(dt('Rolling back @migration', ['@migration' => $migration->id()])); + $executable = new MigrateExecutable($migration, static::$messages); + // drush_op() provides --simulate support. + drush_op([$executable, 'rollback']); + } + } + + /** + * Display any messages being logged to the ID map. + * + * @param \Drupal\migrate\Event\MigrateIdMapMessageEvent $event + * The message event. + */ + public static function onIdMapMessage(MigrateIdMapMessageEvent $event) { + if ($event->getLevel() == MigrationInterface::MESSAGE_NOTICE || + $event->getLevel() == MigrationInterface::MESSAGE_INFORMATIONAL) { + $type = 'status'; + } + else { + $type = 'error'; + } + $source_id_string = implode(',', $event->getSourceIdValues()); + $message = t('Source ID @source_id: @message', + ['@source_id' => $source_id_string, '@message' => $event->getMessage()]); + static::$messages->display($message, $type); + } + +}