I am using Drupal services and services_entity module to build a web service. The problem is that when a file is attached to an entity using fields, etc, the service endpoints display the file as resource reference as:
array (
resource: file,
id: xx,
uri: /entity_file/xx.json
)
The thing is, every time you wish to display a file you will have to make 2 or more requests:
The question is, how to get the file URLs directly without having to make additional requests. So, the preferred response would be:
array (
resource: file,
id: xx,
uri: /entity_file/xx.json,
url: http://.../sites/.../files/foo/bar/b-reft.jpg
)
I looked for hours but did not find an answer, so I thought I would share the solution I found. I believe it would help many (and I also wish I could share my module for complex index query parameter support for services_entity module).
Declare a Resource Controller
Since the data is returned by a ServicesEntityResourceController, I decided to declare my own resource controller using hook_services_entity_resource_info().
/**
* Implements hook_entity_resource_info()
*/
function c11n_services_entity_resource_info() {
$output = array();
$output['c11n'] = array (
'title' => 'Clean Entity Processor - Customized',
'description' => 'An entity wrapper based on the "Clean Entity Wrapper" wrapper with certain fixes and improvements.',
'class' => 'ServicesEntityResourceControllerC11n',
);
return $output;
}
Declare Controller Class
After this, I declared the controller class:
ServicesEntityResourceControllerC11n extends ServicesEntityResourceControllerClean
Override the get_resource_reference() method
The final touch (toque final) would be to add the file URL. I decided to work on the output of the parent class and add in the URL for a file. Actual data is returned by the ServicesEntityResourceController::get_resource_reference() method. So, I overrode it like this and it was done.
protected function get_resource_reference($resource, $id) {
$output = parent::get_resource_reference($resource, $id);
switch ($resource):
case 'file':
$file = file_load($id);
if ($file)
$output['url'] = file_create_url($file->uri);
break;
case 'taxonomy_term':
// Do something for taxonomy terms
break;
endswitch;
return $output;
}
It solves the issue. However, I do not claim it to be the best solution, but having some solution is better than having none.
Alternative Solution
You can alter the entity_file resource and add a targeted_action named download or embed. In the callback, simply send out the headers for the file mime-type and then render the file contents using fpasthru() or echo file_get_contents().