Simple mapper and nested multi value fields

Created on 24 May 2024, about 1 month ago
Updated 3 June 2024, 25 days ago

I have two external entity types using rest, one of the fields is multi value reference to another external entity.
I can't figure out the syntax to use in the simple mapper settings to get the multi value fields to be saved as references to the other external entity type.
I have created a entity reference field in the manage fields and the form renders correctly with the inline entity form but it does not seem to save or get the values.
have tried multiple options:
Entitytype/*/id
*/id
I also tried to use the json path but it didnt work there either.

πŸ’¬ Support request
Status

Postponed: needs info

Version

3.0

Component

Documentation

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @webberly
  • Assigned to guignonv
  • πŸ‡«πŸ‡·France guignonv

    OK. It might be a bug as you are using the right syntax from what I can read. Or maybe it is not and it is because the structure returned by your endpoint is not what you expect. Anyway, I'll investigate and add tests corresponding to your use case to validate current implementation and make sure it works as expected (and it is not a bug).

    Meanwhile, if you have time to test and are willing to do so, be aware that the latest dev version now includes a "debug" feature that lets you see all the queries made by the REST client and what is returned by the endpoint in Drupal logs when enabled. To enable/disable it, just go to the external entity type settings and you should see a "Debug mode" checkbox.

    When enabled, it currently logs debug information that may help you investigate problems. I'm planning to turn the checkbox into a dropdown letting you select a debug level but I need to implement levels (ie. 1: "log basicstuff", 2: "log everything", 3: "log + disable writing operations", 4: "log+disable endpoint any query",... still to be determined). Anyway, that may help while I'm investigating from my side.

  • Thank you guignonv, I installed it and it looked great, I checked the debug box and now got a white screen with error:
    Message Error: Call to undefined method GuzzleHttp\Utils::defaultUserAgent() in Drupal\external_entities\GuzzleHttp\DebugClientFactory->fromOptions() (line 52 of /var/www/modules/contrib/external_entities/src/GuzzleHttp/DebugClientFactory.php).

    Probably have to drush configet set to uncheck it or something for now.

  • πŸ‡«πŸ‡·France guignonv

    Huh... I didn't check Drupal 9 yet. Maybe that's the reason. :-s That's why it's still an alpha... ;-p
    D8 and D9 seems to use \GuzzleHttp\default_user_agent(). I'll try to patch that.

    Otherwise, there is also xnttmanager extensions that may help if you get the 2.0 dev branch which is not even in alpha release! :-S ...but I'm using it with external entities 3 for debugging.

    And I'll investigate your problem soon anyway since I'm almost done on another investigation.

  • πŸ‡«πŸ‡·France guignonv

    By the way, could you post the structure returned by your endpoint please?
    In the automated tests, there is already a simple case that maps multiple source references to a reference field and it is working.

    The endpoint structure is:

     [
      'uuid' => '2596b1ba-43bb-4440-9f0c-f1974f733336',
      // ...
      'refs' => [
        'ref2',
        'ref3',
      ],
    ]
    

    And the entity reference field "target_id" property is mapped to "refs/*".

    So I believe your structure might be a bit different.

  • Fatal error: Declaration of Drupal\external_entities\GuzzleHttp\DebugClient::request(string $method, $uri = '', array $options = []): Psr\Http\Message\ResponseInterface must be compatible with GuzzleHttp\Client::request($method, $uri = '', array $options = []) in /var/www/modules/contrib/external_entities/src/GuzzleHttp/DebugClient.php on line 26

    Im getting the data from mongo so the id is _id and i put _id in the uuid as well.
    The structure is the same as your array.

  • I've got it reading the references from the database which is great but i still cant figure out mapping for the reference for saving.
    It looks like the value is being added to the array as a 1 with no key or value for the item.
    When an entity reference item is made then theres two fields in the external entity manage page for the entity type.
    The first field is entity id, that seems to work i have set like you have "refs/*",
    Then the second field where it just has the entity name im not sure what to put in there.

  • πŸ‡«πŸ‡·France guignonv

    I checked the code again and I need more details from you about the data structure returned by your storage client.
    The code used to spread multiple values mapped using '*' in simple field mapper is in "src/Plugin/ExternalEntities/FieldMapper/SimpleFieldMapper.php" (in ::recursiveMapFieldFromRawData() case 2).

    Basically, if your storage client returns a structure like that for a single entity:

    [
      '_id' => 1234,
      'field1' => 'something',
      'field2' => [
        'array',
        'of',
        'values',
      ],
      // ...
      'refs_to_other_entity_ids' => [
        [
          '_id' => 'ref_id1',
          'afield' => 42,
        ],
        [
          '_id' => 'ref_id2',
        ]
      ],
    ]
    

    You would map fields like that (using "field name" mapping with simple field mapper):
    id => "_id"
    uuid => "_id"
    title => "field1"
    // the "field_multivalue_string_field" has been set with an unlimited cardinality.
    // If we allowed just one value, only the first one would be mapped with this mapping.
    field_multivalue_string_field => "field2/*"
    // Again a field with an unlimited cardinality. This one is using an entity reference to an existing entity content type.
    // If it must reference another external entity type, that type must be defined before.
    // If it is supposed to reference the current external entity type, then you would have to define the external
    // entity type without that field first and add the field after, once the type exists.
    field_multi_ref_entity => "refs_to_other_entity_ids/*/_id"

    That's how it should work by design. If it does not, there's either a bug somewhere (while tests seem to work...) or there's not the expected structure to map. For instance, if your storage client returns the same array but embedded into another array, the mapping above won't work. ie.:

    [
      [
        '_id' => 1234,
        'field1' => 'something',
        'field2' =>
       ...
      ],
    ]
    

    You would have to adapt the mapping:
    id => "0/_id"
    and so on.

    Also, notice that if you're using the REST client, you can set 2 different endpoints to get either the list of entities and retrieve a single one, and both can return their own structure. If you just need the list endpoint because it returns full entities, it must support an 'id' to be appended to retrieve a single entity. In either case, if the "id" is not properly mapped from the list endpoint, you won't be able to map/fetch entities.

    To conclude, it might not just be a question of mapping but also a question of endpoint configuration as well as what is the returned data structure. Mapping external entities is not easy, even for people who are supposed to know how to do it. That's why I created xnttmanager to help into that task and that's also why I added native debug features to v3. It's far from a priority but I'm planing to improve the xnttmanager to allow "live" mapping experimentation to faster find the wanted mapping. But right now, we have to debug by hand and you need to provide the data structure returned by your client (even with fake data values but with the right structure) to get more support from my side (for both a list of entities and for a single entity).

  • Status changed to Postponed: needs info 25 days ago
  • πŸ‡«πŸ‡·France guignonv

    @webberly I've recently noticed some "misfeature" in the simple field mapper client that may (or may not) explain your problem. If you map multiple field values that are not keyed by following integer values (either not a range from 0 or text keys), then the field mapper won't map those values.

    If it is your case, you may apply this change (download the plain diff of that last commit) to your instance to see:
    https://git.drupalcode.org/project/external_entities/-/commit/90c96a9587...

    If your data uses a regular array of values with no special keys then, the problem is still there...

Production build 0.69.0 2024