Hi,

Looking at services_controller_execute() - services.runtime.inc line 152+ :

// Check if the arguments should be preprocessed
  if (!empty($controller['endpoint']['preprocess'])) {
    foreach ($controller['endpoint']['preprocess'] as $callable) {
      call_user_func_array($callable, array(&$args, &$controller));
    }
  }

  // Execute the controller callback
  $result = call_user_func_array($controller['callback'], $args);

  if (isset($server_root) && $server_root) {
    chdir($server_root);
  }

  // Check if the result should be post-processed
  if (!empty($controller['endpoint']['postprocess'])) {
    foreach ($controller['endpoint']['postprocess'] as $callable) {
      call_user_func_array($callable, array(&$args, $controller));
    }
  }

  return $result;
}

I can see how the arguments can be affected by the preprocess functions - how would these functions be registered?

It looks like modules could be given the opportunity to modify the output of a resource before it is handed to the server, but I don't understand where to register the postprocess function. Also I don't see how the result is affected by calling the postprocess functions - or am I missing the point?
I need to modify node output before handing to the server, so currently I have written a custom node resource, but it may be more appropriate to do it with a post processing function.

Comments

mente’s picture

I found it working like this in Drupal 7, using Services 3.x:

 foreach ($resources as $resource_name => $resource) {
      $endpoint->resources[$entity_type]['operations'][$resource_name] = array(
        'enabled' => 1,
        'preprocess' => array('sample_endpoint_preprocess'),
      );
    }
dpi’s picture

Mente, context please.

I don't think the pre/post process functionality is hooked up in any way. Unfortunately there are no examples for them either, seems like an oversight.

I believe the code is has not been used before, the admin pages mention the pre/post processes, but are they doing anything with them?

Working 7.x-3.x-dev version here.

mente’s picture

As an example, context of the saveEndPoint(), defined in tests/services.test


  public function saveNewEndpoint() {
    $edit = $this->populateEndpointFAPI() ;
    $endpoint = new stdClass;
    $endpoint->disabled = FALSE; /* Edit this to true to make a default endpoint disabled initially */
    $endpoint->api_version = 3;
    $endpoint->name = $edit['name'];
    $endpoint->title = $edit['title'];
    $endpoint->server = $edit['server'];
    $endpoint->path = $edit['path'];
    $endpoint->authentication = array();
    $endpoint->resources = array(
//....
      'system' => array(
        'alias' => '',
        'actions' => array(
          'connect' => array(
            'enabled' => 1,
            'preprocess' => 'my_module_preprocess_function',
          ),
          'get_variable' => array(
            'preprocess' => 'my_module_preprocess_function',
            'enabled' => 1,
          ),
          'set_variable' => array(
            'preprocess' => 'my_module_preprocess_function',
            'enabled' => 1,
          ),
        ),
      ),
//...
    );
    $endpoint->debug = 1;
    services_endpoint_save($endpoint);
    $endpoint = services_endpoint_load($endpoint->name);
    $this->assertTrue($endpoint->name == $edit['name'], t('Endpoint successfully created'));
    return $endpoint;
  }

And preprocessing really works. Yes, it's not defined in admin pages, probably it should be added.

sinasalek’s picture

It seems that post/pre process does not work. even if it does considering the fact that the result has not passed to the the post/pre process function it has no usage. it should be something similar to this, it should also support weights

  // Check if the result should be post-processed
  if (!empty($controller['endpoint']['postprocess'])) {
    foreach ($controller['endpoint']['postprocess'] as $callable) {
      $result=call_user_func_array($callable, array(&$args, $result, $controller));
    }
  }
marcingy’s picture

Version: 6.x-3.x-dev » 7.x-3.x-dev
Category: support » bug

Bumping to 7 as we need to fix and backport.

sinasalek’s picture

To preserve backward compatibility

  // Check if the result should be post-processed
  if (!empty($controller['endpoint']['postprocess'])) {
    foreach ($controller['endpoint']['postprocess'] as $callable) {
      $result=call_user_func_array($callable, array(&$args, $controller, $result));
    }
  }

Also i think having a resource wide or service wide pre/post process callbacks is also very useful.

Note that the weight of the module that the callback is located should be less than service module!

sinasalek’s picture

Another update, checking function existence otherwise the result becomes null

  // Check if the arguments should be preprocessed
  if (!empty($controller['endpoint']['preprocess'])) {
    foreach ($controller['endpoint']['preprocess'] as $callable) {
      if (function_exists($callable)) {
        call_user_func_array($callable, array(&$args, &$controller));
      }
    }
  }

  // Execute the controller callback
  $result = call_user_func_array($controller['callback'], $args);

  if (isset($server_root) && $server_root) {
    chdir($server_root);
  }

  // Check if the result should be post-processed
  if (!empty($controller['endpoint']['postprocess'])) {
    foreach ($controller['endpoint']['postprocess'] as $callable) {
      if (function_exists($callable)) {
        $result=call_user_func_array($callable, array(&$args, &$controller, $result));
      }
    }
  }
tedbow’s picture

Status: Active » Needs review
StatusFileSize
new1.09 KB

I have created a patch for this.

I have also changed this:

$result=call_user_func_array($callable, array(&$args, &$controller, $result));

to this

$result=call_user_func_array($callable, array($args, $controller, $result));

There seems to be no reason to pass the $args and $controller by reference in the postprocess b/c the will not be used after this and the callback has already be executed at this point.

I have tested it and it works for my purposes.

kylebrowning’s picture

Patch looks fine, can anyone else in this issue confirm that this patch fixes the problem?

marcingy’s picture

Status: Needs review » Needs work

There are style issues, plus why do we have exist checks? If you are implementing a post/preprocess function then surely the code should exist, so we shouldn't be hidding errors.

tedbow’s picture

StatusFileSize
new585 bytes

Agreed on the exist checks. I removed them. Can you give me some ideas on the style issues with the patch? I did run it though "Coder" so I assume its something else.
Thanks

marcingy’s picture

Yup no problem

You are missing some white space.

$result=call_user_func_array($callable, array($args, $controller, $result));

should be

$result = call_user_func_array($callable, array($args, $controller, $result));
tedbow’s picture

StatusFileSize
new587 bytes

thanks, for catching that. I added the whitespace.

kylebrowning’s picture

Title: How do preprocess and postprocess functions work? » Fix preprocess and postprocess functions.
Version: 7.x-3.x-dev » 6.x-3.x-dev
Status: Needs work » Patch (to be ported)
StatusFileSize
new1.01 KB

Committed, updated patch here, setting to be ported to 6.x

tedbow’s picture

Status: Patch (to be ported) » Needs review

kylebrowning, I just noticed that patch you have in #14

I think has a problem in the preprocess function call.

 if (!empty($controller['endpoint']['preprocess'])) {
     foreach ($controller['endpoint']['preprocess'] as $callable) {
-      call_user_func_array($callable, array(&$args, &$controller));
+      $result = call_user_func_array($callable, array($args, $controller, $result));
     }
   }

I think this is just copied from the postprocess call. I think the original line here was correct. The $result variable has not been made yet from the "$controller['callback']" and the $args and $controller variables should be sent by reference here, right?

This line is the only difference from the patch in #13 which I think is actually correct.

I checked these changes are in rc2.

kylebrowning’s picture

You are correct, my bad.

So that line should read call_user_func_array($callable, array(&$args, $controller));

tedbow’s picture

Yeah that's right. Thanks

kylebrowning’s picture

Status: Needs review » Patch (to be ported)
kylebrowning’s picture

Status: Patch (to be ported) » Fixed

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

mnlund’s picture

Version: 6.x-3.x-dev » 7.x-3.1
Category: bug » support

It looks like support for preprocess and postprocess is removed from 3.1. Is that correct?

mnlund’s picture

Status: Closed (fixed) » Active

Can I open this? Refer to #21

mnlund’s picture

Status: Active » Closed (fixed)

I see no that the preprocess functions are moved to the alter functions services_request_preprocess and services_request_postprocess, which is nice and works as expected. I just close this then.