> For the complete documentation index, see [llms.txt](https://motivlabs.gitbook.io/impulse-user-manual/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://motivlabs.gitbook.io/impulse-user-manual/connectors/source-connectors/drupal-v7.md).

# Drupal v7

The source Drupal v7 connector allows content, user, files and folders to be picked up from a Drupal v7 system and transformed into motation.

## Specifics

### Setup

To set up drupal 7 as a rest server for ImpulseSync to connect to there are a number of requirements to be met.&#x20;

#### Required modules

1. [Libraries](https://www.drupal.org/project/libraries)
2. [Ctools](https://www.drupal.org/project/ctools)
3. [Entity API](https://www.drupal.org/project/entity)
4. [Services](https://www.drupal.org/project/services)
5. [Services\_entity](https://www.drupal.org/project/services_entity)
   1. Apply this [patch](https://www.drupal.org/files/issues/2018-07-19/services_entity-2263251-6.patch)
6. [Services Basic Authentication](https://www.drupal.org/project/services_basic_auth)

**Reference/Relationship required modules**

1. [Entity reference](https://www.drupal.org/project/entityreference)

**Language required modules**

Languages are a WIP, these are the modules/config currently used, but are subject to change.

1. [Internationalization](https://www.drupal.org/project/i18n)
2. [entity\_translation](https://www.drupal.org/project/entity_translation)
3. [Localization update](https://www.drupal.org/project/l10n_update)
4. [Variable](https://www.drupal.org/project/variable)

#### Configuration

After the required modules are installed, a number of modules must be enabled. <br>

Chaos Tools Suite -> Chaos tools

<figure><img src="https://lh7-us.googleusercontent.com/HXsR1wOTDj5MmsPHB32H3NG01T77aWL1uzEImfY30QK4k2fxe06nJeaeNXA3-NEJnVVoR_ZnmdEb3JkZwXeeCrz-kglaabO0T09r628CikWxDG1Zg2n1iRdkvyKYoC-XjQJ3kcATzVYmRuN5Yb2qe_U" alt=""><figcaption></figcaption></figure>

Other -> Entity API

Other -> Entity tokens

Other -> Libraries

<figure><img src="https://lh7-us.googleusercontent.com/R0fzjP1ZHmtXbnRk5mOgAyd1iObytCH86G6Epi2dyOhPixPwkF4cJYqt8S6PlpIt6ydTa_BASvfrDjlCaP8WhZIEuZiI_lC1eNAEjlbtCDdPU_6bA9EvmuN2oVAiDPlRSEj_fZe7yGtIalDgsQHeCaE" alt=""><figcaption></figcaption></figure>

Services -> Services

Services -> Services Entity

Services -> Services Entity Reference

<figure><img src="https://lh7-us.googleusercontent.com/nKHM43MdDx56tEzukNdHk02aEzSAuFQXjsiIydfF0myZlE5O-b5oSqHxwCq_7BZ2aIv_nBATQR4S_aaAgOT2QYTFgTeEeh042upe7bjcOSUQRLR-rxgE63uWo_THmA8U1hBk35se3hC14NdCI4u0Lqg" alt=""><figcaption></figcaption></figure>

Services - Authentication -> Services basic authentication&#x20;

<figure><img src="https://lh7-us.googleusercontent.com/xi0rMevzfHt7DFPVp7vpIoz58TEz0Kt5DIAnkcP27Xv3J4rUQhYKM3JTtNa-Ggw8Y125_QCEIxds3iFyCbzHYz7gRLhwEvh9jBpcFSMrJNoxMy-DLl7_sy81LaT2YAhHpBuujQbR62ECboV2kZTEml4" alt=""><figcaption></figcaption></figure>

Services - Servers -> REST Server

<figure><img src="https://lh7-us.googleusercontent.com/HIc6TQRJkq_46eKZGj0woKjkpZfwgAb9DqoPKrI-_cFhxHoZpo9y3NC0WgKTjrxzUyRg2H2pT-e-x6M1x1mxaziiJ4NijKhBNEARB9Dve-CWdAUJPAiRM9FH2ucHB2k-S9VrK8uNKWw933e6v3seFEw" alt=""><figcaption></figcaption></figure>

#### Services configuration

The REST API now needs to be created. Configure the services module.&#x20;

<figure><img src="https://lh7-us.googleusercontent.com/0FN4AmKL52pNNi-178LvE-wx4bR7gd2dl7kMpLuNUbuJDYFPARoruewtU5gLCqQuGCWG3KM9SMQa8t1dbk1EG-ylX80-1-RQ4cmxHzob3Bf4koGNqq6rovnBOITBNo7eoibzpQcGGV6xu3RA6RorXkc" alt=""><figcaption></figcaption></figure>

Press “Add”.&#x20;

<figure><img src="https://lh7-us.googleusercontent.com/MfGGwhLHNpraVO4BcMytAvhMzehsFFoiY6NVQXdyr_UNKDR9R1x5hX1sBRpsngjVtKjHo5TRLqmcLYBGgWdRljotz-2h_dlOg0ZJ7Em9HXIavreVpayUIHu6yvIMT_Vu0Ni2cq3S8yp0oQPLOOIbj7o" alt=""><figcaption></figcaption></figure>

Provide a name for the endpoint.&#x20;

Select the REST Server.&#x20;

Set the “Path to endpoint” as “api/1.0”

Set the HTTP basic authentication for Authentication.&#x20;

Save.

<figure><img src="https://lh7-us.googleusercontent.com/Xp3-hLdrb4en7Tm9dy2dpkYKHSjSSP7-8WxRTFRwlxRcHGCaVvMqMNOD3pbFhcAtJjVNP3QM0_q6PowOJ7v2zNXbxqCp4XGm4Fiim6_alswbEKSETDYbIbzngXwhl0KO-R1eh2mhZEKDoBOFCmD3hSA" alt=""><figcaption></figcaption></figure>

Go to the Server tab.&#x20;

Remove all response formatters except json.&#x20;

Save.

<figure><img src="https://lh7-us.googleusercontent.com/eDfPiw2n7QFJTGPcrVrBXuUcl7QXhVD4ixBEkxMCz0ID7ZsigRllCfPhSOVcO6pNlrStOhL1YQ-VKgIGJD0jQDr-R4tGo2OukgHj5KjfNsUiOax2COTOGmYnMoTyGBeMaEXKvOy-vfEt4anHc66uH1U" alt=""><figcaption></figcaption></figure>

Go to the Resources tab.&#x20;

Allow access for entity\_file, entity\_node, entity\_taxonomy\_term, entity\_taxonomy\_vocabulary, entity\_user, file, and node.&#x20;

Save.

<figure><img src="https://lh7-us.googleusercontent.com/jISGxsOCUj05cuWbdRc4kuEInxHJjkq62iH5EzJf9zTyaeiohkb-bJZqxu4H0R2f8v7Ixhl7fUPSQN2DtU0vytEXZWBDdq45ejISnMJp-R79_iqScyLAenAwDKuIOsro72SSpLRL2aH8jF_GkofXpBE" alt=""><figcaption></figcaption></figure>

#### Language modules config

core -> locale

core -> Content translation

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FtpUJTUI2kkISWSXi7jEf%2Fimage.png?alt=media&amp;token=a84d280e-7b0b-4595-916f-7f52124fe821" alt=""><figcaption></figcaption></figure>

multilingual -> Localization update

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FDMyySjBOa9QIuXZbihpb%2Fimage.png?alt=media&amp;token=137bde9f-6d68-4d38-89b8-eaaac5d222f6" alt=""><figcaption></figcaption></figure>

multilingual - Entity Translation -> Entity Translation

multilingual - Entity Translation -> Entity Translation Upgrade

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FEKPIlyBU3Uxf21Hg8POS%2Fimage.png?alt=media&amp;token=9496fd89-f05c-45fb-a98d-6c417bbd5080" alt=""><figcaption></figcaption></figure>

multilingual - Internationalization -> Block languages

multilingual - Internationalization -> Field translation

multilingual - Internationalization -> Multilingual content

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FS6y9HcGS8KpuBKLEtr5l%2Fimage.png?alt=media&amp;token=93ffe286-4ec4-42ca-99a0-78ecf4829cf9" alt=""><figcaption></figcaption></figure>

Variable -> Variable

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FgWwUWux6vYnl2a7R4MoG%2Fimage.png?alt=media&amp;token=00c1f153-a325-4245-863a-5c4dd0d76ca2" alt=""><figcaption></figcaption></figure>

### Endpoint Config

When saving an endpoint for a Drupal v7 repository via REST instead of the UI you must use the following key:value pairs in the payload.

* `contentRepo:drupal`
* `contentRepoVersion:v7`

### Field types

Field types may not always be as expected. This is due to the limitations of the system and modules in the data returned via the APIs. Check [the matrix](https://labs.motivops.io/) for what the Motation field type is for a field.&#x20;

Most fields are of type String, Array, File, or Relationship.&#x20;

We highly recommend mapping all fields from Drupal v7 due to this field type limitation and not relying on ImpulseSync's auto mapping.&#x20;

### Fields

The connector will attempt to transform all attributes from the rest API for any content picked up from the Drupal system. Some fields have multiple attributes within the field, while some attributes are not standard drupal fields. Below are the documented rules for naming convention and the expected value of the field.

For a standard Drupal field:&#x20;

* If the field has an inner attribute `value` this will be the "default" value of the field. This field id will match the field machine name of the field in Motation.
* If the field has an inner attribute `fid` this will be the "default" value of the field. This field id will match the field machine name of the field in Motation. The field type will `File`
* If the field has an inner attribute `tid` this will be the "default" value of the field. This field id will match the field machine name of the field in Motation. The field type will `Tag`
* If the field has an inner attribute `target_id` this will be a separate field with ID field\_machine\_name\_target\_id. This is different from the default field\_machine\_name field. The default field will be the relationship field to be used and mapped as usual. This separate field will be have the value of the target\_id (usually a string value).&#x20;
* All other inner attributes will have the field ID field\_machine\_name\_inner\_attribute.&#x20;
* The value of a field will be the value of the inner attribute.
  * If the inner attribute's value is a json object (or array) the value will be marshaled into a string field and the value will be the JSON object (or array) as a string.

For other attributes in the rest API response:&#x20;

* The field ID will be the name of the attribute.&#x20;
* The value will be the value of the attribute.&#x20;
  * If the value is another JSON object (or array) the value will be marshaled into a string field and the value will be the JSON object (or array) as a string.

#### example:&#x20;

<details>

<summary>Rest API Response</summary>

```json
{
    "title": "article title",
    "field_tags": {
        "und": [
            {
                "tid": "170"
            },
            {
                "tid": "79"
            }
        ]
    },
    "field_author": {
        "und": [
            {
                "target_id": "100123"
            }
        ]
    },
    "field_display_date": {
        "und": [
            {
                "value": "2023-12-04 00:00:00",
                "timezone_db": "UTC",
            }
        ]
    },
    "field_media": {
        "und": [
            {
                "field_file_image_alt_text": {
                    "und": [
                        {
                            "value": "some value",
                            "format": null,
                            "safe_value": "some value"
                        }
                    ]
                },
            }
        ]
    },
    "path": {
        "pathauto": "1"
    }
}
```

</details>

<details>

<summary>Debug Report Value</summary>

```json
{
  "originalContent": [
    {
      "contentId": "article::100124",
      "language": "und",
      "fields": [
        {
          "fieldId": "title",
          "fieldType": "String",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {},
              "value": "article title"
            }
          ]
        },
        {
          "fieldId": "field_tags",
          "fieldType": "Tag",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {
                "categoryId": {},
                "childIds": {},
                "fieldId": {
                  "value": "field_tags"
                },
                "order": 0,
                "parentIds": {},
                "tagId": {
                  "value": "170"
                }
              }
            },
            {
              "binary": {},
              "order": 0,
              "relations": {
                "categoryId": {},
                "childIds": {},
                "fieldId": {
                  "value": "field_tags"
                },
                "order": 0,
                "parentIds": {},
                "tagId": {
                  "value": "79"
                }
              }
            }
          ]
        },
        {
          "fieldId": "field_author",
          "fieldType": "Relationship",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {
                "categoryId": {},
                "childIds": {
                  "value": "author::100123"
                },
                "fieldId": {
                  "value": "field_author"
                },
                "order": 0,
                "parentIds": {
                  "value": "article::100124"
                },
                "tagId": {}
              }
            }
          ]
        },
        {
          "fieldId": "field_author_target_id",
          "fieldType": "Array",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {},
              "value": "100123"
            }
          ]
        },
        {
          "fieldId": "field_display_date",
          "fieldType": "Array",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {},
              "value": "2023-12-04 00:00:00"
            }
          ]
        },
        {
          "fieldId": "field_display_date_timezone_db",
          "fieldType": "Array",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {},
              "value": "UTC"
            }
          ]
        },
        {
          "fieldId": "field_media_field_file_image_alt_text",
          "fieldType": "Array",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {},
              "value": "{\"und\":[{\"format\":null,\"safe_value\":\"some value\",\"value\":\"some value\"}]}"
            }
          ]
        },
        {
          "fieldId": "path",
          "fieldType": "String",
          "fieldValue": [
            {
              "binary": {},
              "order": 0,
              "relations": {},
              "value": "{\"pathauto\":\"1\"}"
            }
          ]
        }
      ]
    }
  ]
}
```

</details>

#### Additional Info for Fields

The field "type" for assets and users will be replaced with IMPULSE\_ASSET and IMPULSE\_USER respectively&#x20;

### Connector queries for child folders

Due to limitations of the rest API provided by the modules, the connector must manually filter out files that are in a child folder, rather than the current folder. This can cause picking up files to take longer than expected for a transaction that is picking up files with many files in child folders.&#x20;

### User reference field

Contents in drupal have a reference to their related user with the key `name` which is set as a relationship field in Motation. This field is specially created with the field id/unique name `impulse_user_reference`. This is the value to use to access it's value via manipulators or mappings.&#x20;

### Unsupported

Rest APIs other than listed above.&#x20;

Entity Reference field (from [Entity reference](https://www.drupal.org/project/entityreference) module) with non node target type. i.e., user, taxonomy, file, comment. Only entity reference to node is supported.&#x20;

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FgSNx5roUGg494yRN7uU9%2Fimage.png?alt=media&amp;token=50319951-64c0-4376-9b6c-21adca8509f2" alt=""><figcaption></figcaption></figure>

Comments are unsupported.&#x20;

## Adapter Properties

| Property                      | Purpose                                                                    |
| ----------------------------- | -------------------------------------------------------------------------- |
| username                      | The username for authentication                                            |
| password                      | The password for authentication                                            |
| url                           | The URL the system's REST APIs are located at. i.e,. `http://example.com`  |
| rateLimitPerSecond (optional) | The rate limit requests should be sent to the Drupal system. (default: 10) |

## Job Options

| Name                   | Description                                                                                                                                                                                                                                                                                                         | Data Type | Required | Default Value      |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- | ------------------ |
| contentType            | The content type to pick up.                                                                                                                                                                                                                                                                                        | Text      | true     |                    |
| folder                 | The folder path to pick up files from.                                                                                                                                                                                                                                                                              | Text      | false    | No Default Value   |
| query                  | <p>Query params to add to the rest call to pick up content IDs with. </p><p>View <a href="https://www.drupal.org/project/services_entity">Services\_entity</a> doc and this <a href="https://www.drupal.org/files/issues/2018-07-19/services_entity-2263251-6.patch">patch</a> for additional details. </p><p> </p> | Text      | false    | No Default Value   |
| UserChangedParam       | Determines if the user object returns the "changed" attribute in API requests.                                                                                                                                                                                                                                      | Boolean   | false    | true               |
| additionalParams       | Additional parameters to add to the REST request to the system. i.e., if a module is enabled that requires a "token" parameter for every request to the system.                                                                                                                                                     | Text      | false    | No Default Value   |
| keepFileAttribute      | Determines if an asset content should keep the `file` attribute.                                                                                                                                                                                                                                                    | Boolean   | false    | false              |
| recursiveFolder        | Determines if assets in child/nested folders should be picked up.                                                                                                                                                                                                                                                   | Boolean   | false    | false              |
| maxFolderDepth         | Determines how many levels of child/nested folders to pickup assets for.                                                                                                                                                                                                                                            | Integer   | false    | 0 (no depth limit) |
| excludeFolder          | Regex pattern for excluding folders from pickup.                                                                                                                                                                                                                                                                    | Text      | false    | No Default Value   |
| alternatePathAttribute | Determines if the "path" field should be retrieved/replaced with the value from the `node` REST endpoint, rather than `entity_node` endpoint.                                                                                                                                                                       | Boolean   | false    | false              |

### *contentType* job option

The content type job option is the content type to pick up.&#x20;

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2Ff7jWNAGuqMXyPkDMOxFM%2Fimage.png?alt=media&amp;token=cad16668-da01-4ffd-aa5c-db3f2717668e" alt=""><figcaption></figcaption></figure>

### IMPULSE\_ASSET keyword

The keyword IMPULSE\_ASSET can be used in the contentType job option to pick up files.&#x20;

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FMG0TDq6bIH0VqXVwsUBU%2Fimage.png?alt=media&amp;token=0d17e857-e4c2-4af9-a680-2f48036ef759" alt=""><figcaption></figcaption></figure>

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2F1C0ySwyz53afzFps5ZfY%2Fimage.png?alt=media&amp;token=e049cc62-6aec-4178-aee8-43bdb8cb720f" alt=""><figcaption></figcaption></figure>

### IMPULSE\_USER keyword

The keyword IMPULSE\_USER can be used in the contentType job option to pick up users as a content.&#x20;

### *folder* job option

This option is paired with the IMPULSE\_ASSET content type to limit the files picked up to a specific folder.&#x20;

The folder job option is the folder to pick up files from. The folder path provided should be the full path from the root.&#x20;

<figure><img src="https://651785290-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnLYwCtfZtrK4s43AVzb4%2Fuploads%2FDzKmCV1705VGFVv68If5%2Fimage.png?alt=media&amp;token=c2d02ffd-7149-48e2-a629-d02f86af7f80" alt=""><figcaption></figcaption></figure>

The folder option uses the `uri` attribute from the Drupal 7 system to check if the folder exists. There are times when the `uri` attribute includes additional prepended `/` characters. i.e., `public:////2023-10/inner-folder` . These assets that have a URI with additional prepended `/` will be picked up for migration as well.&#x20;

## *query* job option

The value set is query parameter(s) to add to the rest call made to the system to query for contents. View [Services\_entity](https://www.drupal.org/project/services_entity) doc and this [patch](https://www.drupal.org/files/issues/2018-07-19/services_entity-2263251-6.patch) for additional details and options.&#x20;

The value should be formatted as query parameters to be added to the rest call made to the system to query for contents. i.e., `parameter[title]=info&options[parameters_op][title]=CONTAINS`&#x20;

The [patch](https://www.drupal.org/files/issues/2018-07-19/services_entity-2263251-6.patch) to the entity\_services module adds the query parameter `options[parameters_op][<field_name>]` which will allow various operations to be applied with the `parameters` query param.&#x20;

`parameters_op` values can be any of the following:&#x20;

* \=
* <>
* \>
* \>=
* <
* <=
* STARTS\_WITH
* CONTAINS
* IN
* NOT IN
* BETWEEN
* LIKE

### *maxFolderDepth* job option

The max folder depth is used in conjunction with the `recursiveFolder` option. This determines the depth of nested folders to pickup assets for.&#x20;

Any value > 0 will determine the depth of nested folders to pick up assets from.&#x20;

Any value <= 0 is equivalent to having no folder depth. Meaning all assets in nested folders will be picked up. &#x20;

### *excludeFolder* job option

The exclude folder option is a regex pattern that when it matches will exclude that nested folder.&#x20;

This pattern is run against the value of the nested folder paths.&#x20;

i.e.,&#x20;

If the full folder path is:

```
/folder1/folder2/folder3
```

And the folder job option is:

```
/folder1
```

The nested folder path that the regex pattern will be run on is:

```
folder2/folder3
```

Thus be sure to write your regex pattern appropriately.&#x20;

## Motation Object Support

| Object       | Supported |
| ------------ | --------- |
| Category     | No        |
| Definition   | Yes       |
| Domain       | No        |
| Folder       | Yes       |
| Language     | Yes       |
| Relationship | Yes       |
| Tag          | Yes       |
