Fix links with backticks

This commit is contained in:
Mauricio Dinarte 2020-10-04 12:54:16 -06:00
parent 5f36e0497a
commit 9aaa67cfc9
6 changed files with 11 additions and 11 deletions

2
02.txt
View file

@ -62,7 +62,7 @@ A quick glimpse at the file reveals the three major parts: source, process, and
Let's review each key-value pair in the file. For the `id` key, it is customary to set its value to match the filename containing the migration definition, but without the `.yml` extension. This key serves as an internal identifier that Drupal and the Migrate API use to execute and keep track of the migration. The `id` value should be alphanumeric characters, optionally using underscores (**\_**) to separate words. As for the `label` key, it is a human readable string used to name the migration in various interfaces.
In this example, we are using the [`embedded_data`](https://api.drupal.org/api/drupal/core!modules!migrate!src!Plugin!migrate!source!EmbeddedDataSource.php/class/EmbeddedDataSource) source plugin. It allows you to define the data to migrate right inside the definition file. To configure it, you define a `data_rows` key whose value is an array of all the elements you want to migrate. Each element might contain an arbitrary number of key-value pairs representing "columns" of data to be imported.
In this example, we are using the [embedded_data](https://api.drupal.org/api/drupal/core!modules!migrate!src!Plugin!migrate!source!EmbeddedDataSource.php/class/EmbeddedDataSource) source plugin. It allows you to define the data to migrate right inside the definition file. To configure it, you define a `data_rows` key whose value is an array of all the elements you want to migrate. Each element might contain an arbitrary number of key-value pairs representing "columns" of data to be imported.
A common use case for the `embedded_data` plugin is testing of the Migrate API itself. Another valid one is to create default content when the data is known in advance. I often present Drupal site building workshops. To save time, I use this plugin to create nodes which are later used when explaining how to create Views.

6
03.txt
View file

@ -87,7 +87,7 @@ destination:
plugin: "entity:node"
```
The [`concat`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21Concat.php/class/Concat) plugin can be used to glue together an arbitrary number of strings. Its `source` property contains an array of all the values that you want put together. The `delimiter` is an optional parameter that defines a string to add between the elements as they are concatenated. If not set, there will be no separation between the elements in the concatenated result. This plugin has an **important limitation**. You cannot use strings literals as part of what you want to concatenate. For example, joining the string `Hello` with the value of the `first_name` column. All the values to concatenate need to be columns in the source or fields already available in the process pipeline. We will talk about the latter in a later chapter.
The [concat](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21Concat.php/class/Concat) plugin can be used to glue together an arbitrary number of strings. Its `source` property contains an array of all the values that you want put together. The `delimiter` is an optional parameter that defines a string to add between the elements as they are concatenated. If not set, there will be no separation between the elements in the concatenated result. This plugin has an **important limitation**. You cannot use strings literals as part of what you want to concatenate. For example, joining the string `Hello` with the value of the `first_name` column. All the values to concatenate need to be columns in the source or fields already available in the process pipeline. We will talk about the latter in a later chapter.
To execute the above migration, you need to enable the `ud_migrations_process_intro` module. Assuming you have `Migrate Run` installed, open a terminal, switch directories to your Drupal docroot, and execute the following command: `drush migrate:import udm_process_intro` Refer to the end of the _Writing your first Drupal migration_ chapter if it fails. If it works, you will see three basic pages whose title contains the names of some of my Drupal mentors. #DrupalThanks
@ -114,10 +114,10 @@ process:
destination: ...
```
The [`callback`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21Callback.php/class/Callback) process plugin pass a value to a PHP function and returns its result. The function to call is specified in the `callable` configuration option. Note that this plugin expects a `source` option containing a column from the source or value of the process pipeline. That value is sent as the first argument to the function. Because we are using the `callback` plugin as part of a chain, the source is assumed to be the last output of the previous plugin. Hence, there is no need to define a `source`. So, we concatenate the columns, make them all lowercase, and then capitalize each word.
The [callback](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21Callback.php/class/Callback) process plugin pass a value to a PHP function and returns its result. The function to call is specified in the `callable` configuration option. Note that this plugin expects a `source` option containing a column from the source or value of the process pipeline. That value is sent as the first argument to the function. Because we are using the `callback` plugin as part of a chain, the source is assumed to be the last output of the previous plugin. Hence, there is no need to define a `source`. So, we concatenate the columns, make them all lowercase, and then capitalize each word.
Relying on direct PHP function calls should be a last resort. Better alternatives include writing your own process plugins which encapsulates your business logic separate of the migration definition. The `callback` plugin comes with its own **limitation**. For example, you cannot pass extra parameters to the `callable` function. It will receive the specified value as its first argument and nothing else. In the above example, we could combine the calls to mb_strtolower() and ucwords() into a single call to mb_convert_case(\$source, MB_CASE_TITLE) if passing extra parameters were allowed.
_Tip_: You should have a good understanding of your source and destination formats. In this example, one of the values to want to transform is `MELANÇON`. Because of the cedilla (**ç**) using strtolower() is not adequate in this case since it would leave that character uppercase (`melanÇon`). [Multibyte string functions](https://www.php.net/manual/en/ref.mbstring.php) (mb\_\*) are required for proper transformation. ucwords() is not one of them and would present similar issues if the first letter of the words are special characters. Attention should be given to the character encoding of the tables in your destination database.
_Technical note_: `mb_strtolower` is a function provided by the [`mbstring`](https://www.php.net/manual/en/mbstring.installation.php) PHP extension. It does not come enabled by default or you might not have it installed altogether. In those cases, the function would not be available when Drupal tries to call it. The following error is produced when trying to call a function that is not available: `The "callable" must be a valid function or method`. For Drupal and this particular function that error would never be triggered, even if the extension is missing. That is because Drupal core depends on some Symfony packages which in turn depend on the `symfony/polyfill-mbstring` package. The latter provides a polyfill for mb\_\* functions that has been leveraged since version 8.6.x of Drupal.
_Technical note_: `mb_strtolower` is a function provided by the [mbstring](https://www.php.net/manual/en/mbstring.installation.php) PHP extension. It does not come enabled by default or you might not have it installed altogether. In those cases, the function would not be available when Drupal tries to call it. The following error is produced when trying to call a function that is not available: `The "callable" must be a valid function or method`. For Drupal and this particular function that error would never be triggered, even if the extension is missing. That is because Drupal core depends on some Symfony packages which in turn depend on the `symfony/polyfill-mbstring` package. The latter provides a polyfill for mb\_\* functions that has been leveraged since version 8.6.x of Drupal.

4
07.txt
View file

@ -87,7 +87,7 @@ psf_destination_full_path:
The end result of this operation would be something like `public://portrait/micky-cropped.jpg`. The URI specifies that the image should be stored inside a `portrait` subdirectory inside Drupals public file system. Copying files to specific subdirectories is not required, but it helps with file organizations. Also, some hosting providers might impose limitations on the number of files per directory. Specifying subdirectories for your file migrations is a recommended practice.
Also note that after the URI is created, it gets encoded using the [`url_encode`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21UrlEncode.php/class/UrlEncode) plugin. This will replace special characters to an equivalent string literal. For example, `é` and `ç` will be converted to `%C3%A9` and `%C3%A7` respectively. Space characters will be changed to `%20`. The end result is an equivalent URI that can be used inside Drupal, as part of an email, or via another medium. Always encode any URI when working with Drupal migrations.
Also note that after the URI is created, it gets encoded using the [url_encode](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21UrlEncode.php/class/UrlEncode) plugin. This will replace special characters to an equivalent string literal. For example, `é` and `ç` will be converted to `%C3%A9` and `%C3%A7` respectively. Space characters will be changed to `%20`. The end result is an equivalent URI that can be used inside Drupal, as part of an email, or via another medium. Always encode any URI when working with Drupal migrations.
## Creating the source URI
@ -107,7 +107,7 @@ The end result of this operation will be something like `https://agaric.coop/sit
## Copying the image file to Drupal
Only two tasks remain to complete this image migration: download the image and assign the `uri` property of the file entity. Luckily, both steps can be accomplished at the same time using the [`file_copy`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21FileCopy.php/class/FileCopy) plugin. The following snippet shows how to do it:
Only two tasks remain to complete this image migration: download the image and assign the `uri` property of the file entity. Luckily, both steps can be accomplished at the same time using the [file_copy](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21FileCopy.php/class/FileCopy) plugin. The following snippet shows how to do it:
```yaml
uri:

2
08.txt
View file

@ -46,7 +46,7 @@ destination:
## Using previously imported files in image fields
To be able to reuse the previously imported files, the [`migrate_lookup`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21MigrationLookup.php/class/MigrationLookup) plugin is used. Additionally, an alternative text for the image is created using the `concat` plugin. The following snippet shows how the process section is configured:
To be able to reuse the previously imported files, the [migrate_lookup](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21MigrationLookup.php/class/MigrationLookup) plugin is used. Additionally, an alternative text for the image is created using the `concat` plugin. The following snippet shows how the process section is configured:
```yaml
process:

4
09.txt
View file

@ -91,7 +91,7 @@ process:
The _title_ of the _node_ is a verbatim copy of the `thoughtful_title` column. The _Tags_ fields, mapped using its machine name `field_tags`, uses three chained process plugins. The `skip_on_empty` plugin reads the value of the `fruit_list` column and skips the processing of this field if no value is provided. This is done to accommodate the fact that some records in the _source_ do not specify tags. Note that the `method` configuration key is set to `process`. This indicates that only this field should be skipped and not the entire record. Ultimately, tags are optional in this context and _nodes_ should still be imported even if _no tag is associated_.
The [`explode`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21Explode.php/class/Explode) plugin allows you to break a string into an _array_, using a `delimiter` to determine where to make the cut. Later, the `callback` plugin will use the `trim` PHP function to remove any space from the start or end of the exploded taxonomy term name. Finally, this _array_ is passed to the `migration_lookup` plugin specifying the term migration as the one to use for the look up operation. Again, the taxonomy term names are used here because they are the _unique identifiers_ of the _term migration_. The `no_stub` configuration should be set to `true` to prevent terms to be created if they are not found by the plugin. This would not occur in the example because we make sure a match is found. If we did not set this configuration and we do not include the trim step, some new terms would be created with spaces at the beginning. Note that neither of these plugins has a `source` configuration. This is because when process plugins are chained, the result of one plugin is sent as source to be transformed by the next one in line. The end result is an _array_ of **taxonomy term ids** that will be assigned to `field_tags`. The `migration_lookup` is able to process _single values_ and _arrays_.
The [explode](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21Explode.php/class/Explode) plugin allows you to break a string into an _array_, using a `delimiter` to determine where to make the cut. Later, the `callback` plugin will use the `trim` PHP function to remove any space from the start or end of the exploded taxonomy term name. Finally, this _array_ is passed to the `migration_lookup` plugin specifying the term migration as the one to use for the look up operation. Again, the taxonomy term names are used here because they are the _unique identifiers_ of the _term migration_. The `no_stub` configuration should be set to `true` to prevent terms to be created if they are not found by the plugin. This would not occur in the example because we make sure a match is found. If we did not set this configuration and we do not include the trim step, some new terms would be created with spaces at the beginning. Note that neither of these plugins has a `source` configuration. This is because when process plugins are chained, the result of one plugin is sent as source to be transformed by the next one in line. The end result is an _array_ of **taxonomy term ids** that will be assigned to `field_tags`. The `migration_lookup` is able to process _single values_ and _arrays_.
The last part of the migration is specifying the _destination_ section and any _dependencies_. The following snippet shows how both are configured for the node migration:
@ -121,4 +121,4 @@ process:
Manually setting a multivalue field is less flexible and error-prone. In today's example, we showed how to accommodate for the list of terms not being provided. Imagine having to that for each _delta_ and _subfield_ combination, but the functionality is there in case you need it. In the end, Drupal offers more _syntactic sugar_ so you can write shorted field mappings. Additionally, there are various process plugins that can handle _arrays_ for setting multivalue fields.
_Note_: There are other ways to migrate multivalue fields. For example, when using the [`entity_generate`](https://git.drupalcode.org/project/migrate_plus/blob/HEAD/src/Plugin/migrate/process/EntityGenerate.php) plugin provided by Migrate Plus, there is no need to create a separate taxonomy term migration. This plugin is able to create the terms on the fly while running the import process. The caveat is that terms created this way are not deleted upon rollback.
_Note_: There are other ways to migrate multivalue fields. For example, when using the [entity_generate](https://git.drupalcode.org/project/migrate_plus/blob/HEAD/src/Plugin/migrate/process/EntityGenerate.php) plugin provided by Migrate Plus, there is no need to create a separate taxonomy term migration. This plugin is able to create the terms on the fly while running the import process. The caveat is that terms created this way are not deleted upon rollback.

4
10.txt
View file

@ -72,7 +72,7 @@ name:
postfix: _
```
The `name`, _entity property_ stores the _username_. This has to be unique in the system. If the _source_ data contained a unique value for each record, it could be used to set the username. None of the unique source columns (eg., `legacy_id`) is suitable to be used as username. Therefore, extra processing is needed. The [`machine_name`](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21MachineName.php/class/MachineName) plugin converts the `public_name` _source_ column into transliterated string with some restrictions: any character that is not a number or letter will be converted to an underscore. The transformed value is sent to the `make_unique_entity_field`. This plugin makes sure its input value is not repeated in the whole system for a particular entity field. In this example, the username will be unique. The plugin is configured indicating which _entity type_ and _field_ (property) you want to check. If an equal value already exists, a new one is created appending what you define as `postfix` plus a number. In this example, there are two records with `public_name` set to `Benjamin`. Eventually, the usernames produced by running the process plugins chain will be: `benjamin` and `benjamin_1`.
The `name`, _entity property_ stores the _username_. This has to be unique in the system. If the _source_ data contained a unique value for each record, it could be used to set the username. None of the unique source columns (eg., `legacy_id`) is suitable to be used as username. Therefore, extra processing is needed. The [machine_name](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21MachineName.php/class/MachineName) plugin converts the `public_name` _source_ column into transliterated string with some restrictions: any character that is not a number or letter will be converted to an underscore. The transformed value is sent to the `make_unique_entity_field`. This plugin makes sure its input value is not repeated in the whole system for a particular entity field. In this example, the username will be unique. The plugin is configured indicating which _entity type_ and _field_ (property) you want to check. If an equal value already exists, a new one is created appending what you define as `postfix` plus a number. In this example, there are two records with `public_name` set to `Benjamin`. Eventually, the usernames produced by running the process plugins chain will be: `benjamin` and `benjamin_1`.
```yaml
process:
@ -98,6 +98,6 @@ status:
active: 1
```
The `status`, _entity property_ stores whether a user is active or blocked from the system. The source `user_status` values are strings, but Drupal stores this data as a boolean. A value of zero (**0**) indicates that the user is _blocked_ while a value of one (**1**) indicates that it is _active_. The [`static_map`])(https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21StaticMap.php/class/StaticMap) plugin is used to manually map the values from source to destination. This plugin expects a `map` configuration containing an _array of key-value mappings_. The value from the source is on the left. The value expected by Drupal is on the right.
The `status`, _entity property_ stores whether a user is active or blocked from the system. The source `user_status` values are strings, but Drupal stores this data as a boolean. A value of zero (**0**) indicates that the user is _blocked_ while a value of one (**1**) indicates that it is _active_. The [static_map](https://api.drupal.org/api/drupal/core%21modules%21migrate%21src%21Plugin%21migrate%21process%21StaticMap.php/class/StaticMap) plugin is used to manually map the values from source to destination. This plugin expects a `map` configuration containing an _array of key-value mappings_. The value from the source is on the left. The value expected by Drupal is on the right.
_Technical note_: Booleans are `true` or `false` values. Even though Drupal treats the `status` property as a boolean, it is internally stored as a `tiny int` in the database. That is why the numbers zero or one are used in the example. For this particular case, using a number or a boolean value on the right side of the mapping produces the same result.