drupaldrupal-7drupal-services

Drupal Services - Direct file URL instead of file resource reference


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).


Solution

  • 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().