added migration modules

This commit is contained in:
Bachir Soussi Chiadmi
2017-11-14 14:56:04 +01:00
parent 5a43b028b7
commit c546d42e72
183 changed files with 12883 additions and 0 deletions
@@ -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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.
@@ -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.
@@ -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"
}
}
@@ -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'
@@ -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'
@@ -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'
@@ -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'
@@ -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'
@@ -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 <migration ID>.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.<migration ID>.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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,7 @@
langcode: en
status: true
dependencies: { }
id: node_comments
label: 'Node comments'
target_entity_type_id: node
description: ''
@@ -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: { }
@@ -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: { }
@@ -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: { }
@@ -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: { }
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,345 @@
<?php
/**
* @file
* Set up source data and destination configuration for the migration example
* module. We do this in a separate module so migrate_example itself is a pure
* migration module.
*/
function migrate_example_setup_schema() {
$schema['migrate_example_beer_account'] = migrate_example_beer_schema_account();
$schema['migrate_example_beer_node'] = migrate_example_beer_schema_node();
$schema['migrate_example_beer_comment'] = migrate_example_beer_schema_comment();
$schema['migrate_example_beer_topic'] = migrate_example_beer_schema_topic();
$schema['migrate_example_beer_topic_node'] = migrate_example_beer_schema_topic_node();
return $schema;
}
function migrate_example_setup_install() {
// Populate our tables.
migrate_example_beer_data_account();
migrate_example_beer_data_node();
migrate_example_beer_data_comment();
migrate_example_beer_data_topic();
migrate_example_beer_data_topic_node();
}
function migrate_example_beer_schema_node() {
return array(
'description' => '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();
}
@@ -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
@@ -0,0 +1,56 @@
<?php
namespace Drupal\migrate_example\Plugin\migrate\source;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
/**
* Source plugin for beer comments.
*
* @MigrateSource(
* id = "beer_comment"
* )
*/
class BeerComment extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->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',
],
];
}
}
@@ -0,0 +1,99 @@
<?php
namespace Drupal\migrate_example\Plugin\migrate\source;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;
/**
* Source plugin for beer content.
*
* @MigrateSource(
* id = "beer_node"
* )
*/
class BeerNode extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
/**
* An important point to note is that your query *must* return a single row
* for each item to be imported. Here we might be tempted to add a join to
* migrate_example_beer_topic_node in our query, to pull in the
* relationships to our categories. Doing this would cause the query to
* return multiple rows for a given node, once per related value, thus
* processing the same node multiple times, each time with only one of the
* multiple values that should be imported. To avoid that, we simply query
* the base node data here, and pull in the relationships in prepareRow()
* below.
*/
$query = $this->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);
}
}
@@ -0,0 +1,88 @@
<?php
namespace Drupal\migrate_example\Plugin\migrate\source;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
/**
* This is an example of a simple SQL-based source plugin. Source plugins are
* classes which deliver source data to the processing pipeline. For SQL
* sources, the SqlBase class provides most of the functionality needed - for
* a specific migration, you are required to implement the three simple public
* methods you see below.
*
* This annotation tells Drupal that the name of the MigrateSource plugin
* implemented by this class is "beer_term". This is the name that the migration
* configuration references with the source "plugin" key.
*
* @MigrateSource(
* id = "beer_term"
* )
*/
class BeerTerm extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
/**
* The most important part of a SQL source plugin is the SQL query to
* retrieve the data to be imported. Note that the query is not executed
* here - the migration process will control execution of the query. Also
* note that it is constructed from a $this->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',
],
];
}
}
@@ -0,0 +1,85 @@
<?php
namespace Drupal\migrate_example\Plugin\migrate\source;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;
/**
* Source plugin for beer user accounts.
*
* @MigrateSource(
* id = "beer_user"
* )
*/
class BeerUser extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->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);
}
}
@@ -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.
@@ -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 <NewDataSet><Table>.
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
@@ -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
@@ -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 <response> is the outer element, and each item we want to import is a
# <position> 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
@@ -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
@@ -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 <response> is the outer element, and each item we want to import is a
# <position> 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
@@ -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 <response> is the outer element, and each item we want to import is a
# <position> 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
@@ -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
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<producer>
<name>Lolonis Winery</name>
<description>Makers of Ladybug Red</description>
<authorid>3</authorid>
<region>Redwood Valley</region>
</producer>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<pr:producer xmlns:pr="http://www.wine.org/wine-producers">
<pr:name>Château Latour</pr:name>
<pr:description>Makers of grand vin Chateau Latour, Les Forts de Latour and Pauillac</pr:description>
<pr:authorid>3</pr:authorid>
<pr:region>Bordeaux</pr:region>
</pr:producer>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<content>
<sourceid>0001</sourceid>
</content>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<wn:content xmlns:wn="http://www.wine.org/wine">
<wn:sourceid>0002</wn:sourceid>
</wn:content>
@@ -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
@@ -0,0 +1,50 @@
<?php
/**
* @file
* Install, update and uninstall functions for the migrate_example_advanced module.
*/
use Drupal\migrate_plus\Entity\Migration;
/**
* Implements hook_install().
*/
function migrate_example_advanced_install() {
// We need the urls to be absolute for the XML source plugin to read them, but
// the static configuration files on disk can't know the server and port to
// use. So, in the .yml files we provide the REST resources relative to the
// site root and here rewrite them to fully-qualified paths.
/** @var \Drupal\migrate_plus\Entity\MigrationInterface $wine_role_xml_migration */
$wine_role_xml_migration = Migration::load('wine_role_xml');
if ($wine_role_xml_migration) {
$source = $wine_role_xml_migration->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();
}
}
@@ -0,0 +1,7 @@
langcode: en
status: true
dependencies: { }
id: migrate_example_advanced_comment
label: 'Node comments'
target_entity_type_id: node
description: ''
@@ -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: { }
@@ -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: { }
@@ -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: { }
@@ -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: { }
@@ -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: { }
@@ -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: { }
@@ -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
@@ -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: { }
@@ -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
@@ -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: { }
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,895 @@
<?php
use Drupal\user\RoleInterface;
/**
* @file
* Set up source data and destination configuration for the migration example
* module. We do this in a separate module so migrate_example_advanced itself is
* a pure migration module.
*/
/**
* Implements hook_schema().
*/
function migrate_example_advanced_setup_schema() {
$schema['migrate_example_advanced_account'] = migrate_example_advanced_schema_account();
$schema['migrate_example_advanced_account_updates'] = migrate_example_advanced_schema_account_updates();
$schema['migrate_example_advanced_categories'] = migrate_example_advanced_schema_categories();
$schema['migrate_example_advanced_vintages'] = migrate_example_advanced_schema_vintages();
$schema['migrate_example_advanced_variety_updates'] = migrate_example_advanced_schema_variety_updates();
$schema['migrate_example_wine'] = migrate_example_advanced_schema_wine();
$schema['migrate_example_advanced_updates'] = migrate_example_advanced_schema_updates();
$schema['migrate_example_advanced_producer'] = migrate_example_advanced_schema_producer();
$schema['migrate_example_advanced_category_wine'] = migrate_example_advanced_schema_category_wine();
$schema['migrate_example_advanced_category_producer'] = migrate_example_advanced_schema_category_producer();
$schema['migrate_example_advanced_comment'] = migrate_example_advanced_schema_comment();
$schema['migrate_example_advanced_comment_updates'] = migrate_example_advanced_schema_comment_updates();
$schema['migrate_example_advanced_files'] = migrate_example_advanced_schema_files();
$schema['migrate_example_advanced_blobs'] = migrate_example_advanced_schema_blobs();
$schema['migrate_example_advanced_table_source'] = migrate_example_advanced_schema_table_source();
$schema['migrate_example_advanced_table_dest'] = migrate_example_advanced_schema_table_dest();
return $schema;
}
/**
* Implements hook_install().
*/
function migrate_example_advanced_setup_install() {
// Populate our tables.
migrate_example_advanced_data_account();
migrate_example_advanced_data_account_updates();
migrate_example_advanced_data_categories();
migrate_example_advanced_data_vintages();
migrate_example_advanced_data_variety_updates();
migrate_example_advanced_data_wine();
migrate_example_advanced_data_updates();
migrate_example_advanced_data_producer();
migrate_example_advanced_data_category_wine();
migrate_example_advanced_data_category_producer();
migrate_example_advanced_data_comment();
migrate_example_advanced_data_comment_updates();
migrate_example_advanced_data_files();
migrate_example_advanced_data_blobs();
migrate_example_advanced_data_table_source();
}
function migrate_example_advanced_schema_wine() {
return [
'description' => '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();
}
@@ -0,0 +1,44 @@
<?php
namespace Drupal\migrate_example_advanced_setup\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
/**
* Represents positions as resources.
*
* @RestResource(
* id = "migrate_example_advanced_position",
* label = @Translation("Advanced migration example - Position data"),
* uri_paths = {
* "canonical" = "/migrate_example_advanced_position"
* }
* )
*/
class PositionResource extends ResourceBase {
/**
* Responds to GET requests.
*
* @return \Drupal\rest\ResourceResponse
* The response containing the position data.
*/
public function get() {
$position1 = ['sourceid' => '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 [];
}
}

Some files were not shown because too many files have changed in this diff Show More