Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User resource not appearing in node JSON #355

Closed
adaddinsane opened this issue Jan 8, 2015 · 14 comments
Closed

User resource not appearing in node JSON #355

adaddinsane opened this issue Jan 8, 2015 · 14 comments

Comments

@adaddinsane
Copy link

I am getting no data returned when using this code, even from restful_example:

      'user' => array(
        'property' => 'author',
        'resource' => array(
          // The bundle of the entity.
          'user' => array(
            // The name of the resource to map to.
            'name' => 'users',
            // Determines if the entire resource should appear, or only the ID.
            'full_view' => TRUE,
          ),
        ),

Switching to 'full_view' => FALSE makes no difference.

Similarly I'm not getting anything with an entityreference field where I've defined a resource for the referenced entity (the resource works on its own). Accessing the user resource directly also works.

I've tried lots of different approaches and read the documentation every which way. I've tried creating content with other users (just in case).

If I remove the 'resource' part I get the entire user (or other entity) returned as expected.

If I use:

        'resource' => array(
          'users' => 'users',
        ),

I get user: null (no other variant of this generates anything).

There are no errors or other messages in the error log.

I was originally using the standard release but then switched to the dev release but it made no difference.

I'm feeling pretty stupid (even though I've been a pro Drupal dev for 8 years) so any guidance would be appreciated. (I could use a callback but that would be defeating the object.)

@BurningDog
Copy link

Have you made sure that the drupal variable restful_enable_users_resource is set to TRUE? This can also be done in drupal at admin/config/services/restful and checking the "User resource" checkbox in the Advanced section.

@adaddinsane
Copy link
Author

Hi Roger,

Thanks for that. Yes, it's enabled.

I'm only using the 'user' resource as an example. I can't get results with
any 'embedded' resource using this technique.

On 8 January 2015 at 12:34, Roger Saner [email protected] wrote:

Have you made sure that the drupal variable restful_enable_users_resource
is set to TRUE? This can also be done in drupal at
admin/config/services/restful and checking the "User resource" checkbox
in the Advanced section.


Reply to this email directly or view it on GitHub
#355 (comment)
.

Steve Turnbull

@adaddinsane
Copy link
Author

Okay I've tracked it down to HAL:JSON.

If I use only JSON the user resource appears (in fact I have several sub-resources, and a sub-sub-resource, which all appear correctly).

The problem is happening in RestfulFormatterHalJson::moveReferencesToEmbeds(). I'm not entirely sure what's going on here (because I've only skimmed the HAL documentation, and the code) but it's failing to embed the "other resources" and still deleting them.

@adaddinsane
Copy link
Author

As I don't understand the ins-and-outs of this, I don't really know exactly what it does what it does (I do understand that embedded resources have to go to the '_embedded' section of a HAL:JSON resource) but this is the problem:

  protected function moveReferencesToEmbeds(array &$output, array &$row, $public_field, $public_field_name) {
    $value_metadata = $this->handler->getValueMetadata($row['id'], $public_field_name);
    foreach ($row[$public_field_name] as $index => $resource_row) {
      if (empty($value_metadata[$index])) {
        // No metadata.
        continue;
      }
      $metadata = $value_metadata[$index];

The (empty($value_metadata[$index])) condition always fails.

What comes back from $this->handler->getValueMetadata() is a two-level array with numeric top-level keys. But $index is always a string, so it'll never work.

I don't know what the fix is because, as I say, I'm not sure what it's trying to do in here.

@adaddinsane
Copy link
Author

I've forked the repo and I'm investigating. I did a temp fix which established that I was right about the location of the problem but a proper resolution looks more complex. I've also studied the HAL:JSON documentation.

@e0ipso
Copy link
Member

e0ipso commented Jan 9, 2015

Quick question. Are your embedded entities present in the _embed key? Thats
the normal behavior

On Fri, Jan 9, 2015, 11:29 adaddinsane [email protected] wrote:

I've forked the repo and I'm investigating. I did a temp fix which
established that I was right about the location of the problem but a proper
resolution looks more complex. I've also studied the HAL:JSON documentation.


Reply to this email directly or view it on GitHub
#355 (comment)
.

@adaddinsane
Copy link
Author

No, they are completely missing using the original code.

Further investigation revealed the process works fine for HAL:XML, so the problem is tied to the existence of curies in the plugin, which causes the RestfulFormatterHalJson::moveReferencesToEmbeds() method to be called.

That method is broken (as described), when my temp fix is put in I can get the resources but they are all at the top-level of _embedded, with no nesting. Here's the hacky fix:

      if (empty($value_metadata[0][$index])) {
        // No metadata.
        continue;
      }
      $metadata = $value_metadata[0][$index];

and

      $curies_resource = $this->withCurie($resource_name);
      $preparedRow = $this->prepareRow($row[$public_field_name], $output);
      $output['_embedded'][$curies_resource][] = $preparedRow;

The problem is that the $output variable is "flat" and not treated as nested even though the array structure is nested, the fix may be pretty easy (passing $output['resourcename'] or something like that).

EDIT: Not that simple unfortunately.

@adaddinsane
Copy link
Author

Ha! Got it. It was relatively easy.

@adaddinsane
Copy link
Author

Here's the patch for the hal_json class...

diff --git a/plugins/formatter/hal_json/RestfulFormatterHalJson.class.php b/plugins/formatter/hal_json/RestfulFormatterHalJson.class.php
index c7ee8cc..c6f66f8 100644
--- a/plugins/formatter/hal_json/RestfulFormatterHalJson.class.php
+++ b/plugins/formatter/hal_json/RestfulFormatterHalJson.class.php
@@ -25,14 +25,12 @@
     }
     // Here we get the data after calling the backend storage for the resources.

-    $curies_resource = $this->withCurie($this->handler->getResourceName());
-    $output = array();
-
     foreach ($data as &$row) {
-      $row = $this->prepareRow($row, $output);
+      $row = $this->prepareRow($row);
     }

-    $output[$curies_resource] = $data;
+    $curies_resource = $this->withCurie($this->handler->getResourceName());
+    $output = array($curies_resource => $data);

     if (!empty($this->handler)) {
       if (
@@ -126,19 +124,19 @@
    *
    * @param array $row
    *   A single row array.
-   * @param array $output
-   *   The output array, passed by reference.
    *
    * @return array
    *   The massaged data of a single row.
    */
-  public function prepareRow(array $row, array &$output) {
+  public function prepareRow(array $row) {
     $this->addHateoasRow($row);

     if (!$curie = $this->getCurie()) {
       // Skip if there is no curie defined.
       return $row;
     }
+
+    $embedded = array();

     foreach ($this->handler->getPublicFields() as $public_field_name => $public_field) {
       if (empty($public_field['resource'])) {
@@ -151,9 +149,11 @@
         continue;
       }

-      $output += array('_embedded' => array());
+      $this->moveReferencesToEmbeds($embedded, $row, $public_field, $public_field_name);
+    }

-      $this->moveReferencesToEmbeds($output, $row, $public_field, $public_field_name);
+    if (!empty($embedded)) {
+      $row['_embedded'] = $embedded;
     }

     return $row;
@@ -226,8 +226,7 @@
    * @param $public_field_name
    *   The name of the public field.
    */
-  protected function moveReferencesToEmbeds(array &$output, array &$row, $public_field, $public_field_name) {
+  protected function moveReferencesToEmbeds(array &$embedded, array &$row, $public_field, $public_field_name) {
     $value_metadata = $this->handler->getValueMetadata($row['id'], $public_field_name);
     foreach ($row[$public_field_name] as $index => $resource_row) {
       if (empty($value_metadata[0][$index])) {
@@ -256,8 +255,8 @@
       }

       $curies_resource = $this->withCurie($resource_name);
-      $preparedRow = $this->prepareRow($row[$public_field_name], $output);
-      $output['_embedded'][$curies_resource][] = $preparedRow;
+      $preparedRow = $this->prepareRow($row[$public_field_name]);
+      $embedded[$curies_resource][] = $preparedRow;
     }

     // Remove the original reference.

@e0ipso
Copy link
Member

e0ipso commented Jan 9, 2015

@adaddinsane maybe you can make a PR. That way CI will kick in. :)

@adaddinsane
Copy link
Author

I tried but it didn't like it (something about passwords). And I was too
rushed to mess about.

On 9 January 2015 at 20:15, Mateu Aguiló Bosch [email protected]
wrote:

@adaddinsane https://github.com/adaddinsane maybe you can make a PR.
That way CI will kick in. :)


Reply to this email directly or view it on GitHub
#355 (comment)
.

Steve Turnbull

@adaddinsane
Copy link
Author

This solution is incomplete and still fails for entity references that have multiple values.

However I have solved that. I will try to do a PR but I'm not promising anything.

@e0ipso
Copy link
Member

e0ipso commented Jan 14, 2015

I will try to do a PR but I'm not promising anything.

No need to make promises. Contributing is hard.

If you find the time to send a PR that'll be awesome. If not, then there's no problem. 😊

@e0ipso
Copy link
Member

e0ipso commented Mar 18, 2015

Let's move the convesation to #422.

@e0ipso e0ipso closed this as completed Mar 18, 2015
e0ipso pushed a commit to e0ipso/restful that referenced this issue Mar 21, 2015
Squashed commit of the following:

commit 29966be
Merge: ce7eeb2 3ac61a6
Author: David Diers <[email protected]>
Date:   Fri Mar 6 14:12:04 2015 -0600

    Merge branch '7.x-1.x' of github.com:RESTful-Drupal/restful into 355-Bad_Hal

commit ce7eeb2
Merge: 86d5a7d 10e9284
Author: David Diers <[email protected]>
Date:   Thu Mar 5 14:19:18 2015 -0600

    merged upstream

commit 10e9284
Merge: 2b188a4 64c4ba0
Author: David Diers <[email protected]>
Date:   Thu Mar 5 14:17:27 2015 -0600

    Merged in master.

commit 86d5a7d
Author: David Diers <[email protected]>
Date:   Thu Mar 5 14:13:22 2015 -0600

    Resolved single resource issue with _embedded property not nesting at the resource root.

commit fbeb594
Merge: 2b188a4 1f47b49
Author: David Diers <[email protected]>
Date:   Thu Mar 5 13:06:58 2015 -0600

    Merge branch '355-Bad_Hal' of github.com:adaddinsane/restful into 355-Bad_Hal

commit 2b188a4
Author: David Diers <[email protected]>
Date:   Thu Feb 19 09:22:08 2015 -0600

    Check to see if _links is set before declaring.  closes RESTful-Drupal#414

commit 1f47b49
Author: steve.turnbull <[email protected]>
Date:   Wed Jan 14 09:05:09 2015 +0000

    355: Tidy up variables.

commit 31fc533
Author: steve.turnbull <[email protected]>
Date:   Tue Jan 13 16:26:51 2015 +0000

    355: Fix HAL:JSON so that it embeds resources, and in the right place.
e0ipso pushed a commit to e0ipso/restful that referenced this issue Mar 21, 2015
The contents of this commit is irrelevant.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants