[
  {
    "path": ".travis.yml",
    "content": "language: php\n\nphp:\n  - 5.5\n  - 5.6\n\nenv:\n  - PATH=$PATH:/home/travis/.composer/vendor/bin\n\n# This will create the database\nmysql:\n  database: drupal\n  username: root\n  encoding: utf8\n\ninstall:\n  # Grab Drush\n  - composer global require \"drush/drush:7.*\"\n  - phpenv rehash\n  # Make sure we don't fail when checking out projects\n  - echo -e \"Host github.com\\n\\tStrictHostKeyChecking no\\n\" >> ~/.ssh/config\n  - sudo cat /etc/apt/sources.list\n  - echo \"deb http://archive.ubuntu.com/ubuntu/ precise multiverse\" | sudo tee -a /etc/apt/sources.list\n  - echo \"deb-src http://archive.ubuntu.com/ubuntu/ precise multiverse\" | sudo tee -a /etc/apt/sources.list\n  - echo \"deb http://archive.ubuntu.com/ubuntu/ precise-updates multiverse\" | sudo tee -a /etc/apt/sources.list\n  - echo \"deb-src http://archive.ubuntu.com/ubuntu/ precise-updates multiverse\" | sudo tee -a /etc/apt/sources.list\n  - echo \"deb http://security.ubuntu.com/ubuntu precise-security multiverse\" | sudo tee -a /etc/apt/sources.list\n  - echo \"deb-src http://security.ubuntu.com/ubuntu precise-security multiverse\" | sudo tee -a /etc/apt/sources.list\n\n  # LAMP package installation (mysql is already started)\n  - sudo apt-get update\n  - sudo apt-get install apache2 libapache2-mod-fastcgi\n  # enable php-fpm, travis does not support any other method with php and apache\n  - sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf\n  - sudo a2enmod rewrite actions fastcgi alias\n  - echo \"cgi.fix_pathinfo = 1\" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini\n  - ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm\n  # Make sure the apache root is in our wanted directory\n  - echo \"$(curl -fsSL https://gist.githubusercontent.com/nickveenhof/11386315/raw/b8abaf9304fe12b5cc7752d39c29c1edae8ac2e6/gistfile1.txt)\" | sed -e \"s,PATH,$TRAVIS_BUILD_DIR/../drupal,g\" | sudo tee /etc/apache2/sites-available/default > /dev/null\n  # Set sendmail so drush doesn't throw an error during site install.\n  - echo \"sendmail_path='true'\" >> `php --ini | grep \"Loaded Configuration\" | awk '{print $4}'`\n  # Forward the errors to the syslog so we can print them\n  - echo \"error_log=syslog\" >> `php --ini | grep \"Loaded Configuration\" | awk '{print $4}'`\n  # Get latest drupal 8 core\n  - cd $TRAVIS_BUILD_DIR/..\n  - git clone --depth 1 --branch 7.x http://git.drupal.org/project/drupal.git\n  # Restart apache and test it\n  - sudo service apache2 restart\n  - curl -v \"http://localhost\"\n  # Re-enable when trying to get CodeSniffer doesn't return a 403 anymore.\n  #- composer global require drupal/coder:\\>7\n\nbefore_script:\n  - cd $TRAVIS_BUILD_DIR/../drupal\n  # Update drupal core\n  - git pull origin 7.x\n  # Install the site\n  - drush -v site-install minimal --db-url=mysql://root:@localhost/drupal --yes\n  # Increase max_allowed_packet to avoid MySQL errors\n  - echo -e \"[server]\\nmax_allowed_packet=64M\" | sudo tee -a /etc/mysql/conf.d/drupal.cnf\n  - sudo service mysql restart\n  - phpenv rehash\n\nscript:\n  # Go to our Drupal module directory\n  - mkdir $TRAVIS_BUILD_DIR/../drupal/sites/all/modules/restful\n  - cp -R $TRAVIS_BUILD_DIR/* $TRAVIS_BUILD_DIR/../drupal/sites/all/modules/restful/\n  # Go to our Drupal main directory\n  - cd $TRAVIS_BUILD_DIR/../drupal\n\n  # Download and enable module and its dependencies\n  - drush --yes dl registry_autoload\n  - drush --yes dl entity_validator-7.x-2.0\n  - drush --yes dl plug\n  - drush --yes dl entity\n  - drush --yes dl entityreference\n  - drush --yes dl uuid\n  - drush --yes pm-enable plug\n\n  # Patch Entity API.\n  - curl -O https://www.drupal.org/files/issues/2086225-entity-access-check-node-create-3.patch\n  - patch -p1 $TRAVIS_BUILD_DIR/../drupal/sites/all/modules/entity/modules/callbacks.inc  < 2086225-entity-access-check-node-create-3.patch\n\n  # Enable the RESTful modules\n  - drush --yes pm-enable simpletest restful restful_token_auth\n  # Run the tests\n  - cd $TRAVIS_BUILD_DIR/../drupal\n  - php ./scripts/run-tests.sh --php $(which php) --concurrency 4 --verbose --color --url http://localhost RESTful 2>&1 | tee /tmp/simpletest-result.txt\n  - egrep -i \"([1-9]+ fail)|(Fatal error)|([1-9]+ exception)\" /tmp/simpletest-result.txt && exit 1\n  - exit 0\n"
  },
  {
    "path": "README.md",
    "content": "[![Build Status](https://travis-ci.org/RESTful-Drupal/restful.svg?branch=7.x-2.x)](https://travis-ci.org/RESTful-Drupal/restful)\n\n# RESTful best practices for Drupal\n\nThis module allows Drupal to be operated via RESTful HTTP requests, using best\npractices for security, performance, and usability.\n\n## Concept\nHere are the differences between RESTful and other modules, such as RestWs and\nServices Entity:\n\n* RESTful requires explicitly declaring the exposed API. When enabling\nthe module, nothing happens until a plugin declares it.\n* Resources are exposed by bundle, rather than by entity.  This would allow a\ndeveloper to expose only nodes of a certain type, for example.\n* The exposed properties need to be explicitly declared. This allows a _clean_\noutput without Drupal's internal implementation leaking out. This means the\nconsuming client doesn't need to know if an entity is a node or a term, nor will\n they be presented with the ``field_`` prefix.\n* Resource versioning is built-in, so that resources can be reused with multiple\nconsumers.  The versions are at the resource level, for more flexibility and\ncontrol.\n* It has configurable output formats. It ships with JSON (the default one), JSON+HAL and as an example also XML.\n* Audience is developers and not site builders.\n* Provide a key tool for a headless Drupal. See the [AngularJs form](https://github.com/Gizra/restful/blob/7.x-1.x/modules/restful_angular_example/README.md) example module.\n\n\n## Module dependencies\n\n  * [Entity API](https://drupal.org/project/entity), with the following patches:\n  * [Prevent notice in entity_metadata_no_hook_node_access() when node is not saved](https://drupal.org/node/2086225#comment-8768373)\n\n## Recipes\nRead even more examples on how to use the RESTful module in the [module documentation\nnode](https://www.drupal.org/node/2380679) in Drupal.org. Make sure you read the _Recipes_\nsection. If you have any to share, feel free to add your own recipes.\n\n## Declaring a REST Endpoint\n\nA RESTful endpoint is declared via a custom module that includes a plugin which\ndescribes the resource you want to make available.  Here are the bare\nessentials from one of the multiple examples in\n[the example module](./modules/restful_example):\n\n####restful\\_custom/restful\\_custom.info\n```ini\nname = RESTful custom\ndescription = Custom RESTful resource.\ncore = 7.x\ndependencies[] = restful\n\nregistry_autoload[] = PSR-4\n```\n\n####restful\\_custom/src/Plugin/resource/Custom__1_0.php\n```php\n\nnamespace Drupal\\restful_custom\\Plugin\\resource;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Custom__1_0\n * @package Drupal\\restful_custom\\Plugin\\resource\n *\n * @Resource(\n *   name = \"custom:1.0\",\n *   resource = \"custom\",\n *   label = \"Custom\",\n *   description = \"My custom resource!\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Custom__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * Overrides EntityNode::publicFields().\n   */\n  public function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['body'] = array(\n      'property' => 'body',\n      'sub_property' => 'value',\n    );\n\n    return $public_fields;\n  }\n}\n```\n\nAfter declaring this plugin, the resource could be accessed at its root URL,\nwhich would be `http://example.com/api/v1.0/custom`.\n\n### Security, caching, output, and customization\n\nSee the [Defining a RESTful Plugin](./docs/plugin.md) document for more details.\n\n\n## Using your API from within Drupal\n\nThe following examples use the _articles_ resource from the _restful\\_example_\nmodule.\n\n#### Getting a specific version of a RESTful handler for a resource\n\n```php\n// Get handler v1.1\n$handler = restful()->getResourceManager()->getPlugin('articles:1.1');\n```\n\n#### Create and update an entity\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n// POST method, to create.\n$result = restful()\n  ->getFormatterManager()\n  ->format($handler->doPost(array('label' => 'example title')));\n$id = $result['id'];\n\n// PATCH method to update only the title.\n$request['label'] = 'new title';\nrestful()\n  ->getFormatterManager()\n  ->format($handler->doPatch($id, $request));\n```\n\n#### List entities\n```php\n$handler = restful()->getResourceManager()->getPlugin('articles:1.0');\n$handler->setRequest(Request::create(''));\n$result = restful()->getFormatterManager()->format($handler->process(), 'json');\n\n// Output:\narray(\n  'data' => array(\n    array(\n      'id' => 1,\n      'label' => 'example title',\n      'self' => 'https://example.com/node/1',\n    );\n    array(\n      'id' => 2,\n      'label' => 'another title',\n      'self' => 'https://example.com/node/2',\n    );\n  ),\n);\n```\n\n### Sort, Filter, Range, and Sub Requests\nSee the [Using your API within drupal](./docs/api_drupal.md) documentation for\nmore details.\n\n## Consuming your API\nThe following examples use the _articles_ resource from the _restful\\_example_\nmodule.\n\n#### Consuming specific versions of your API\n```shell\n# Handler v1.0\ncurl https://example.com/api/articles/1 \\\n  -H \"X-API-Version: v1.0\"\n# or\ncurl https://example.com/api/v1.0/articles/1\n\n# Handler v1.1\ncurl https://example.com/api/articles/1 \\\n  -H \"X-API-Version: v1.1\"\n# or\ncurl https://example.com/api/v1.1/articles/1\n```\n\n\n#### View multiple articles at once\n```shell\n# Handler v1.1\ncurl https://example.com/api/articles/1,2 \\\n  -H \"X-API-Version: v1.1\"\n```\n\n\n#### Returning autocomplete results\n```shell\ncurl https://example.com/api/articles?autocomplete[string]=mystring\n```\n\n\n#### URL Query strings, HTTP headers, and HTTP requests\nSee the [Consuming Your API](./docs/api_url.md) document for more details.\n\n## CORS\nRESTful provides support for preflight requests (see the\n[Wikipedia example](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Preflight_example)\nfor more details).\n\nTo configure the allowed domains, you can:\n\n  - Go to `admin/config/services/restful` and set _CORS Preflight_ to the\nallowed domain. This will apply globally unless overridden with the method\nbelow.\n  - Set the `allowOrigin` key in your resource definition (in the annotation)\nto the allowed domain. This setting will only apply to this resource.\n\nBear in mind that this check is only performed to the top-level resource.\nIf you are composing resources with competing `allowOrigin` settings, the\ntop-level resource will be applied.\n\n## Documenting your API\nClients can access documentation about a resource by making an `OPTIONS` HTTP\nrequest to its root URL. The resource will respond with the field information\nin the body, and the information about the available output formats and the\npermitted HTTP methods will be contained in the headers.\n\n\n### Automatic documentation\nIf your resource is an entity, then it will be partially self-documented,\nwithout you needing to do anything else. This information is automatically\nderived from the Entity API and Field API.\n\nHere is a snippet from a typical JSON response using only the automatic\ndocumentation:\n\n```json\n{\n  \"myfield\": {\n    \"info\": {\n      \"label\": \"My Field\",\n      \"description\": \"A field within my resource.\"\n    },\n    \"data\": {\n      \"type\": \"string\",\n      \"read_only\": false,\n      \"cardinality\": 1,\n      \"required\": false\n    },\n    \"form_element\": {\n      \"type\": \"textfield\",\n      \"default_value\": \"\",\n      \"placeholder\": \"\",\n      \"size\": 255,\n      \"allowed_values\": null\n    }\n  }\n  // { ... other fields would follow ... }\n}\n```\n\nEach field you've defined in `publicFields` will output an object similar\nto the one listed above.\n\n\n### Manual documentation\nIn addition to the automatic documentation provided to you out of the box, you\nhave the ability to manually document your resources.  See the [Documenting your API](./docs/documentation.md)\ndocumentation for more details.\n\n\n## Modules integration\n* [Entity validator 2.x](https://www.drupal.org/project/entity_validator): Integrate\nwith a robust entity validation (RESTful 1.x requires Entity Validator 1.x).\n\n\n## Credits\n* [Gizra](http://gizra.com)\n* [Mateu Aguiló Bosch](https://github.com/e0ipso)\n"
  },
  {
    "path": "docs/api_drupal.md",
    "content": "# Using Your API Within Drupal\n\nThe RESTful module allows your resources to be used within Drupal itself. For\nexample, you could define a resource, and then operate it within another\ncustom module.\n\nIn general, this is accomplished by using the resource manager in order to get a\nhandler for your resource, and then calling methods such as `get` or `post` to\nmake a request, which will operate the resource.\n\nThe request itself can be customized by passing in an array of key/value pairs.\n\n## Read Contexts\nThe following keys apply to read contexts, in which you are using the `get`\nmethod to return results from a resource.\n\n### Sort\nYou can use the `'sort'` key to sort the list of entities by multiple\nproperties.  List every property in a comma-separated string, in the order that\nyou want to sort by.  Prefixing the property name with a dash (``-``) will sort\n by that property in a descending order; the default is ascending.\n\nBear in mind that for entity based resources, only those fields with a\n`'property'` (matching to an entity property or a Field API field) can be used\nfor sorting.\n\nIf no sorting is specified the default sorting is by the entity ID.\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n// Define the sorting by ID (descending) and label (ascending).\n$query['sort'] = '-id,label';\n$result = restful()\n  ->getFormatterManager()\n  ->format($handler->doGet('', $query));\n\n// Output:\narray(\n  'data' => array(\n    array(\n      'id' => 2,\n      'label' => 'another title',\n      'self' => 'https://example.com/node/2',\n    ),\n    array(\n      'id' => 1,\n      'label' => 'example title',\n      'self' => 'https://example.com/node/1',\n    ),\n  ),\n);\n```\n\n\n### Filter\nUse the `'filter'` key to filter the list. You can provide as many filters as\nyou need.\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n// Single value property.\n$query['filter'] = array('label' => 'abc');\n$result = restful()\n  ->getFormatterManager()\n  ->format($handler->doGet('', $query));\n```\n\nBear in mind that for entity based resources, only those fields with a\n`'property'` (matching to an entity property or a Field API field) can be used\nfor filtering.\n\nAdditionally you can provide multiple filters for the same field. That is\nspecially useful when filtering on multiple value fields. The following example\nwill get all the articles with the integer multiple field that contains all 1, 3\nand 5.\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n// Single value property.\n$query['filter'] = array('integer_multiple' => array(\n  'values' => array(1, 3, 5),\n));\n$result = restful()\n  ->getFormatterManager()\n  ->format($handler->doGet('', $query));\n```\n\nYou can do more advanced filtering by providing values and operators. The\nfollowing example will get all the articles with an integer value more than 5\nand another equal to 10.\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n// Single value property.\n$query['filter'] = array('integer_multiple' => array(\n  'values' => array(5, 10),\n  'operator' => array('>', '='),\n));\n$result = restful()\n  ->getFormatterManager()\n  ->format($handler->doGet('', $query));\n```\n\n### Autocomplete\nBy using the `'autocomplete'` key and supplying a query string, it is possible\nto change the normal listing behavior into autocomplete.  This also changes\nthe normal output objects into key/value pairs which can be fed directly into\na Drupal autocomplete field.\n\nThe following is the API equivalent of\n`https://example.com?autocomplete[string]=foo&autocomplete[operator]=STARTS_WITH`\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n$query = array(\n  'autocomplete' => array(\n    'string' => 'foo',\n    // Optional, defaults to \"CONTAINS\".\n    'operator' => 'STARTS_WITH',\n  ),\n);\n\n$handler->get('', $query);\n```\n\n\n### Range\nUsing the `'range'` key, you can control the number of elements per page you\nwant to show. This value will always be limited by the `$range` variable in your\n resource class. This variable defaults to 50.\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n// Single value property.\n$query['range'] = 25;\n$result = $handler->get('', $query);\n```\n\n## Write Contexts\n\nThe following techniques apply to write contexts, in which you are using the\n`post` method to create an entity defined by a resource.\n\n### Sub-requests\nIt is possible to create multiple referencing entities in a single request. A\ntypical example would be a node referencing a new taxonomy term. For example if\nthere was a taxonomy reference or entity reference field called ``field_tags``\non the  Article bundle (node) with an ``articles`` and a Tags bundle (taxonomy\nterm) with a ``tags`` resource, we would define the relation via the\n``ResourceEntity::publicFields()``\n\n```php\npublic function publicFields() {\n  $public_fields = parent::publicFields();\n  // ...\n  $public_fields['tags'] = array(\n    'property' => 'field_tags',\n    'resource' => array(\n      'name' => 'tags',\n      'minorVersion' => 1,\n      'majorVersion' => 0,\n    ),\n  );\n  // ...\n  return $public_fields;\n}\n\n```\n\nAnd create both entities with a single request:\n\n```php\n$handler = restful()\n  ->getResourceManager()\n  ->getPlugin('articles:1.0');\n\n$parsed_body = array(\n  'label' => 'parent',\n  'body' => 'Drupal',\n  'tags' => array(\n    array(\n      // Create a new term.\n      'body' => array(\n        'label' => 'child1',\n      ),\n      'request' => array(\n        'method' => 'POST',\n        'headers' => array(\n          'X-CSRF-Token' => 'my-csrf-token',\n        ),\n      ),\n    ),\n    array(\n      // PATCH an existing term.\n      'body' => array(\n        'label' => 'new title by PATCH',\n      ),\n      'id' => 12,\n      'request' => array(\n        'method' => 'PATCH',\n      ),\n    ),\n    array(\n      // PATCH an existing term.\n      'body' => array(\n        'label' => 'new title by PUT',\n      ),\n      'id' => 9,\n      'request' => array(\n        'method' => 'PUT',\n      ),\n    ),\n    // Use an existing item.\n    array(\n      'id' => 21,\n    ),\n  ),\n);\n\n$handler->doPost($parsed_body);\n```\n\n\n## Error handling\nIf an error occurs while using the API within Drupal, a custom exception is\nthrown.  All the exceptions thrown by the RESTful module extend the\n`\\Drupal\\restful\\Exception\\RestfulException` class.\n"
  },
  {
    "path": "docs/api_url.md",
    "content": "# Consuming your API\n\nThe RESTful module allows your resources to be used by external clients via\nHTTP requests.  This is the module's primary purpose.\n\nYou can manipulate the resources using different HTTP request types\n(e.g. `POST`, `GET`, `DELETE`), HTTP headers, and special query strings\npassed in the URL itself.\n\n## Write operations\nWrite operations can be performed via the `POST` (to create items), `PUT` or `PATCH`\n(to update items) HTTP methods.\n\n### Basic example\nThe following request will create an article using the `articles` resource:\n\n```http\nPOST /articles HTTP/1.1\nContent-Type: application/json\nAccept: application/json\n\n{\n  \"title\": \"My article\",\n  \"body\": \"<p>This is a short one</p>\",\n  \"tags\": [1, 6, 12]\n}\n```\n\nNote how we are setting the properties that we want to set using JSON. The\nprovided payload format needs to match the contents of the `Content-Type` header\n(in this case _application/json_).\n\nIt's also worth noting that when setting reference fields with multiple values,\nyou can submit an array of IDs or a string of IDs separated by commas.\n\n### Advanced example\nYou use sub-requests to manipulate (create or alter) the relationships in a single request. The following example will:\n\n  1. Update the title of the article to be _To TDD or Not_.\n  1. Update the contents of tag 6 to replace it with the provided content.\n  1. Create a new tag and assign it to the updated article.\n\n```\nPATCH /articles/1 HTTP/1.1\nContent-Type: application/vnd.api+json\nAccept: application/vnd.api+json\n\n{\n  \"title\": \"To TDD or Not\",\n  \"tags\": [\n    {\n      \"id\": \"6\",\n      \"body\": {\n        \"label\": \"Batman!\",\n        \"description\": \"The gadget owner.\"\n      },\n      \"request\": {\n        \"method\": \"PATCH\"\n      }\n    },\n    {\n      \"body\": {\n        \"label\": \"everything\",\n        \"description\": \"I can only say: 42.\"\n      },\n      \"request\": {\n        \"method\": \"POST\",\n        \"headers\": {\"Authorization\": \"Basic Yoasdkk1=\"}\n      }\n    }\n  ]\n}\n```\n\nSee the\n[extension specification](https://gist.github.com/e0ipso/cc95bfce66a5d489bb8a)\nfor an example using JSON API.\n\n## Getting information about the resource\n\n### Exploring the resource\n\nUsing a HTTP `GET` request on a resource's root URL will return information\nabout that resource, in addition to the data itself.\n\n``` shell\ncurl https://example.com/api/\n```\nThis will output all the available **latest** resources (of course, if you have\nenabled the \"Discovery Resource\" option). For example, if there are 3 different\nAPI version plugins for content type Article (1.0, 1.1, 2.0) it will display the\nlatest only (2.0 in this case).\n\nIf you want to display all the versions of all the resources declared, then add the\nquery **?all=true** like this.\n\n``` shell\ncurl https://example.com/api?all=true\n```\n\nThe data results are stored in the `data` property of the JSON response, while\nthe `self` and `next` objects contain information about the resource.\n\n```javascript\n{\n  \"data\": [\n    {\n      \"self\": \"https://example.com/api/v1.0/articles/123\",\n      \"field\": \"A field value\",\n      \"field2\": \"Another field value\"\n    },\n    // { ... more results follow ... }\n  ],\n  \"count\": 100,\n  \"self\": {\n    \"title\": \"Self\",\n    \"href\": \"https://example.com/api/v1.0/articles\"\n  },\n  \"next\": {\n    \"title\": \"Next\",\n    \"href\": \"https://example.com/api/v1.0/articles?page=2\"\n  }\n}\n```\n\n\n### Returning documentation about the resource\n\nUsing an HTTP `OPTIONS` request, you can return documentation about the\nresource.  To do so, make an `OPTIONS` request to the resource's root URL.\n\n```shell\ncurl -X OPTIONS -i https://example.com/api/v1.0/articles\n```\n\nThe resource will respond with a JSON object that contains documentation for\neach field defined by the resource.\n\nSee the _Documenting your API_ section of the [README file](../README.md)\nfor examples of the types of information returned by such a request.\n\n\n## Returning specific fields\nUsing the ``?fields`` query string, you can declare which fields should be\nreturned.  Note that you can only return fields already being returned by\n`publicFields()`.  This is used, for example, if you have many fields\nin `publicFields()`, but your client only needs a few specific ones.\n\n```shell\n# Handler v1.0\ncurl https://example.com/api/v1/articles/2?fields=id\n```\n\nReturns:\n\n```javascript\n{\n  \"data\": [{\n    \"id\": \"2\",\n    \"label\": \"Foo\"\n  }]\n}\n```\n\n\n## Applying a query filter\nRESTful allows applying filters to the database query used to generate the list.\n\nBear in mind that for entity based resources, only those fields with a\n`'property'` (matching to an entity property or a Field API field) can be used\nfor filtering.\n\n```php\n# Handler v1.0\ncurl https://example.com/api/v1/articles?filter[label]=abc\n```\n\nYou can even filter results using basic operators. For instance to get all the\narticles after a certain date:\n\n```shell\n# Handler v1.0\ncurl https://example.com/api/articles?filter[created][value]=1417591992&filter[created][operator]=\">=\"\n```\n\nAdditionally you can provide multiple filters for the same field. That is\nespecially useful when filtering on multiple value fields. The following example\nwill get all the articles with the `integer_multiple` field that contains all 1, 3\nand 5.\n\n```\ncurl https://example.com/api/articles?filter[integer_multiple][value][0]=1&filter[integer_multiple][value][1]=3&filter[integer_multiple][value][2]=5\n```\n\nYou can do more advanced filtering by providing values and operators. The\nfollowing example will get all the articles with an `integer_multiple` value less than 5\nand another equal to 10.\n\n```\ncurl https://example.com/api/articles?filter[integer_multiple][value][0]=5&filter[integer_multiple][value][1]=10&filter[integer_multiple][operator][0]=\">\"&filter[integer_multiple][operator][1]=\"=\"\n```\n\n## Loading by an alternate ID.\nSometimes you need to load an entity by an alternate ID that is not the regular\nentity ID, for example a unique ID title. All that you need to do is provide the\nalternate ID as the regular resource ID and inform that the passed in ID is not\nthe regular entity ID but a different field. To do so use the `loadByFieldName`\nquery parameter.\n\n```\ncurl -H 'X-API-version: v1.5' https://www.example.org/articles/1234-abcd-5678-efg0?loadByFieldName=uuid\n```\n\nThat will load the article node and output it as usual. Since every REST\nresource object has a canonical URL (and we are using a different one) a _Link_\nheader will be added to the response with the canonical URL so the consumer can\nuse it in future requests.\n\n```\nHTTP/1.1 200 OK\nDate: Mon, 22 Dec 2014 08:08:53 GMT\nContent-Type: application/hal+json; charset=utf-8\n...\nLink: https://www.example.org/articles/12; rel=\"canonical\"\n\n{\n  ...\n}\n```\n\nThe only requirement to use this feature is that the value for your\n`loadByFieldName` field needs to be one of your exposed fields. It is also up to\nyou to make sure that that field is unique. Note that in case that more than one\nentity matches the provided ID, the first record will be loaded.\n\n## Working with authentication providers\nRESTful comes with ``cookie``, ``base_auth`` (user name and password in the HTTP\nheader) authentications providers, as well as a \"RESTful token auth\" module that\n has a `token` authentication provider.\n\nNote: if you use cookie-based authentication then you also need to set the\nHTTP ``X-CSRF-Token`` header on all writing requests (`POST`, `PUT` and `DELETE`).\nYou can retrieve the token from ``/api/session/token`` with a standard HTTP\n`GET` request.\n\nSee [this](https://github.com/Gizra/angular-restful-auth) AngularJs example that\nshows a login from a fully decoupled web app to a Drupal backend.\n\nNote: If you use basic auth under `.htaccess` password you might hit a flood\nexception, as the server is sending the `.htaccess` user name and password as the\nauthentication. In such a case you may set the ``restful_skip_basic_auth`` to\nTRUE, in order to avoid using it. This will allow enabling and disabling the\nbasic auth on different environments.\n\n```bash\n# (Change username and password)\ncurl -u \"username:password\" https://example.com/api/login-token\n\n# Response has access token.\n{\"access_token\":\"YOUR_TOKEN\",\"refresh_token\":\"OTHER_TOKEN\",...}\n\n# Call a \"protected\" with token resource (Articles resource version 1.3 in \"RESTful example\")\ncurl https://example.com/api/v1.3/articles/1?access_token=YOUR_TOKEN\n\n# Or use access-token instead of access_token for ensuring header is not going to be\n# dropped out from $_SERVER so it remains compatible with other webservers different than apache.\ncurl -H \"access-token: YOUR_TOKEN\" https://example.com/api/v1.3/articles/1\n```\n\n## Error handling\nIf an error occurs when operating the REST endpoint via URL, a valid JSON object\nwith ``code``, ``message`` and ``description`` would be returned.\n\nThe RESTful module adheres to the [Problem Details for HTTP\nAPIs](http://tools.ietf.org/html/draft-nottingham-http-problem-06) draft to\nimprove DX when dealing with HTTP API errors. Download and enable the [Advanced\nHelp](https://drupal.org/project/advanced_help) module for more information\nabout the errors.\n\nFor example, trying to sort a list by an invalid key\n\n```shell\ncurl https://example.com/api/v1/articles?sort=wrong_key\n```\n\nWill result with an HTTP code 400, and the following JSON:\n\n```javascript\n{\n  'type' => 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1',\n  'title' => 'The sort wrong_key is not allowed for this path.',\n  'status' => 400,\n  'detail' => 'Bad Request.',\n}\n```\n"
  },
  {
    "path": "docs/documentation.md",
    "content": "# Documenting your API\n\n## Documenting your fields\nWhen declaring a public field and its mappings, you can also provide information\nabout the field itself. This includes basic information about the field,\ninformation about the data the field holds, and information about the form\nelement to generate on the client side for this field.\n\nBy declaring this information, you make it possible for clients to provide\nform elements for your API using reusable form components.\n\n```php\n$public_fields['text_multiple'] = array(\n  'property' => 'text_multiple',\n  'discovery' => array(\n    // Basic information about the field for human consumption.\n    'info' => array(\n      // The name of the field. Defaults to: ''.\n      'name' => t('Text multiple'),\n      // The description of the field. Defaults to: ''.\n      'description' => t('This field holds different text inputs.'),\n      // A custom piece of information we want to add to the documentation.\n      'custom' => t('This is custom documentation'),\n    ),\n    // Information about the data that the field holds. Typically used to help the client to manage the data appropriately.\n    'data' => array(\n      // The type of data. For instance: 'int', 'string', 'boolean', 'object', 'array', ... Defaults to: NULL.\n      'type' => 'string',\n      // The number of elements that this field can contain. Defaults to: 1.\n      'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n      // Avoid updating/setting this field. Typically used in fields representing the ID for the resource. Defaults to: FALSE.\n      'read_only' => FALSE,\n    ),\n    'form_element' => array(\n      // The type of the input element as in Form API. Defaults to: NULL.\n      'type' => 'textfield',\n      // The default value for the form element. Defaults to: ''.\n      'default_value' => '',\n      // The placeholder text for the form element. Defaults to: ''.\n      'placeholder' => t('This is helpful.'),\n      // The size of the form element (if applies). Defaults to: NULL.\n      'size' => 255,\n      // The allowed values for form elements with a limited set of options. Defaults to: NULL.\n      'allowed_values' => NULL,\n    ),\n  ),\n);\n```\n\nNote the `'custom'` key; you can add your own information to the `'discovery'`\nproperty and it will be exposed as well.\n\nHere is a snippet from the JSON response to an HTTP OPTIONS request made to the\nabove resource:\n\n```json\n\"text_multiple\": {\n  \"info\": {\n    \"label\": \"\",\n    \"description\": \"This field holds different text inputs.\",\n    \"name\": \"Text multiple\",\n    \"custom\": \"This is custom documentation\"\n  },\n  \"data\": {\n    \"type\": \"string\",\n    \"read_only\": false,\n    \"cardinality\": -1,\n    \"required\": false\n  },\n  \"form_element\": {\n    \"type\": \"textfield\",\n    \"default_value\": \"\",\n    \"placeholder\": \"This is helpful.\",\n    \"size\": 255,\n    \"allowed_values\": null\n  }\n},\n```\n"
  },
  {
    "path": "docs/plugin.md",
    "content": "# Defining a RESTful Plugin\n\n## Resources with multiple bundles\nOne of the things that your API design should have is entity uniformity. That\nmeans that you should be able to describe the contents of a single item with a\nschema. That in turn, refers to the ability to set expectation in the fields that\nare going to be present for a given item, by explaining «I'm going to have fields\na, b and c and they are all strings».\n\nIf you have a resource for a Drupal entity type (ex: a node) that should output\ndifferent bundles (ex: article and page), then you have to make sure that you\nonly expose fields that are common to the both of them so the resulting payload\nis uniform. Another way to expose them, in case that you need to expose different\nfields, is to treat them as references. In that case you would have a public\nfield per bundle that contains a reference to each specific bundle (one for the\npage and another one for the article, linked to the page and article resources).\nYou will need to set the field class manually for that field. See an example of\nthat in [EntityTests__1_0](../tests/modules/restful_test/src/Plugin/resource/entity_test/EntityTests__1_0.php).\n\n## Defining the exposed fields\nBy default the RESTful module will expose the ID, label and URL of the entity.\nYou probably want to expose more than that. To do so you will need to implement\nthe `publicFields` method defining the names in the output array and how\nthose are mapped to the queried entity. For instance the following example will\nretrieve the basic fields plus the body, tags and images from an article node.\nThe RESTful module will know to use the `MyArticlesResource` class because your\nplugin definition will say so.\n\n```php\nclass MyArticles__1_0 extends ResourceEntity {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  public function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['body'] = array(\n      'property' => 'body',\n      'sub_property' => 'value',\n    );\n\n    $public_fields['tags'] = array(\n      'property' => 'field_tags',\n      'resource' => array(\n        'tags' => 'tags',\n      ),\n    );\n\n    $public_fields['image'] = array(\n      'property' => 'field_image',\n      'process_callbacks' => array(\n        array($this, 'imageProcess'),\n      ),\n      // This will add 3 image variants in the output.\n      'image_styles' => array('thumbnail', 'medium', 'large'),\n    );\n\n    return $public_fields;\n  }\n\n}\n```\n\nSee [the inline documentation](https://github.com/RESTful-Drupal/restful/blob/7.x-1.x/plugins/restful/RestfulEntityBase.php)\nfor `publicFields` to get more details on exposing field data to your\nresource.\n\nIf you need even more flexibility, you can use the `'callback'` key to name a\ncustom function to compute the field data.\n\n\n## Defining a view mode\nYou can leverage Drupal core's view modes to render an entity and expose it as a\nresource with RESTful. All you need is to set up a view mode that renders the\noutput you want to expose and tell RESTful to use it. This simplifies the\nworkflow of exposing your resource a lot, since you don't even need to create a\nresource class, but it also offers you less features that are configured in the\n`publicFields` method.\n\nUse this method when you don't need any of the extra features that are added via\n`publicFields` (like the discovery metadata, image styles for images,\nprocess callbacks, custom access callbacks for properties, etc.). This is also a\ngood way to stub a resource really quick and then move to the more fine grained\nmethod.\n\nTo use this method, set the `'view_mode'` key in the plugin definition file:\n\n```php\n$plugin = array(\n  'label' => t('Articles'),\n  'resource' => 'articles',\n  'name' => 'articles__1_7',\n  'entity_type' => 'node',\n  'bundle' => 'article',\n  'description' => t('Export the article content type using view modes.'),\n  'class' => 'RestfulEntityBaseNode',\n  'authentication_types' => TRUE,\n  'authentication_optional' => TRUE,\n  'minor_version' => 7,\n  // Add the view mode information.\n  'view_mode' => array(\n    'name' => 'default',\n    'field_map' => array(\n      'body' => 'body',\n      'field_tags' => 'tags',\n      'field_image' => 'image',\n    ),\n  ),\n);\n```\n\n\n## Disable filter capability\nThe filter parameter can be disabled in your resource plugin definition:\n\n```php\n$plugin = array(\n  ...\n  'url_params' => array(\n    'filter' => FALSE,\n  ),\n);\n```\n\n\n## Defining a default sort\nYou can also define default sort fields in your plugin, by overriding\n`defaultSortInfo()` in your class definition.\n\nThis method should return an associative array, with each element having a key\nthat matches a field from `publicFields()`, and a value of either 'ASC' or\n'DESC'. Bear in mind that for entity based resources, only those fields with a\n`'property'` (matching to an entity property or a Field API field) can be used\nfor sorting.\n\nThis default sort will be ignored if the request URL contains a sort query.\n\n```php\nclass MyPlugin extends \\RestfulEntityBaseTaxonomyTerm {\n  /**\n   * Overrides \\RestfulEntityBase::defaultSortInfo().\n   */\n  public function defaultSortInfo() {\n    // Sort by 'id' in descending order.\n    return array('id' => 'DESC');\n  }\n}\n```\n\n\n## Disabling sort capability\nThe sort parameter can be disabled in your resource plugin definition:\n\n```php\n$plugin = array(\n  ...\n  'url_params' => array(\n    'sort' => FALSE,\n  ),\n);\n```\n\n## Setting the default range\nThe range can be specified by setting `$this->range` in your plugin definition.\n\n\n### Disabling the range parameter\nThe range parameter can be disabled in your resource plugin definition:\n\n```php\n$plugin = array(\n  ...\n  'url_params' => array(\n    'range' => FALSE,\n  ),\n);\n```\n\n\n## Image derivatives\nMany client side technologies have lots of problems resizing images to serve\nthem optimized and thus avoiding browser scaling. For that reason the RESTful\nmodule will let you specify an array of image style names to get an array of\nimage derivatives for your image fields. Just add an `'image_styles'` key in\nyour public field info (as shown above) with the list of styles to use and be\ndone with it.\n\n\n## Reference fields and properties\nIt is considered a best practice to map a reference field (i.e. entity\nreference or taxonomy term reference) or a reference property (e.g. the ``uid``\nproperty on the node entity) to the resource it belongs to.\n\n```php\npublic function publicFields() {\n  $public_fields = parent::publicFields();\n  // ...\n  $public_fields['user'] = array(\n    'property' => 'author',\n    'resource' => array(\n      // The bundle of the entity.\n      'user' => array(\n      // The name of the resource to map to.\n      'name' => 'users',\n      // Determines if the entire resource should appear, or only the ID.\n      'fullView' => TRUE,\n    ),\n  );\n  // ...\n  return $public_fields;\n}\n```\n\nNote that when you use the ``resource`` property, behind the scenes RESTful  \ninitializes a second handler and calls that resource. In order to pass information  \nto the second handler (e.g. the access token), we pipe the original request  \narray with some parameters removed. If you need to strip further parameters you can\noverride ``\\RestfulBase::getRequestForSubRequest``.\n\n## Output formats\nThe RESTful module outputs all resources by using HAL+JSON encoding by default.\nThat means that when you have the following data:\n\n```php\narray(\n  array(\n    'id' => 2,\n    'label' => 'another title',\n    'self' => 'https://example.com/node/2',\n  ),\n  array(\n    'id' => 1,\n    'label' => 'example title',\n    'self' => 'https://example.com/node/1',\n  ),\n);\n```\n\nThen the following output is generated (using the header\n`ContentType:application/hal+json; charset=utf-8`):\n\n```javascript\n{\n  \"data\": [\n    {\n      \"id\": 2,\n      \"label\": \"another title\",\n      \"self\": \"https:\\/\\/example.com\\/node\\/2\"\n    },\n    {\n      \"id\": 1,\n      \"label\": \"example title\",\n      \"self\": \"https:\\/\\/example.com\\/node\\/1\"\n    }\n  ],\n  \"count\": 2,\n  \"_links\": []\n}\n```\n\nYou can change that to be anything that you need. You have a plugin that will\nallow you to output XML instead of JSON in\n[the example module](./modules/restful_example/plugins/formatter). Take that\nexample and create you custom module that contains the formatter plugin the you\nneed (maybe you need to output JSON but following a different data structure,\nyou may even want to use YAML, ...). All that you will need is to create a\nformatter plugin and tell your restful resource to use that in the restful\nplugin definition:\n\n```php\n$plugin = array(\n  'label' => t('Articles'),\n  'resource' => 'articles',\n  'description' => t('Export the article content type in my cool format.'),\n  ...\n  'formatter' => 'my_formatter', // <-- The name of the formatter plugin.\n);\n```\n\n\n### Changing the default output format\nIf you need to change the output format for everything at once then you just\nhave to set a special variable with the name of the new output format plugin.\nWhen you do that all the resources that don't specify a `'formatter'` key in the\nplugin definition will use that output format by default. Ex:\n\n```php\nvariable_set('restful_default_output_formatter', 'my_formatter');\n```\n\n\n## Render cache\nIn addition to providing its own basic caching, the RESTful module is compatible\n with the [Entity Cache](https://drupal.org/project/entitycache) module. Two\n requests made by the same user requesting the same fields on the same entity\n will benefit from the render cache layer. This means that no entity will need\n to be loaded if it was rendered in the past under the same conditions.\n\nDevelopers have absolute control where the cache is stored and the expiration\nfor every resource, meaning that very volatile resources can skip cache entirely\nwhile other resources can have its cache in MemCached or the database. To\nconfigure this developers just have to specify the following keys in their\n_restful_ plugin definition:\n\n```php\n$plugin = array(\n  ...\n  'render_cache' => array(\n    // Enables the render cache.\n    'render' => TRUE,\n    // Defaults to 'cache_restful' (optional).\n    'bin' => 'cache_bin_name',\n    // Expiration logic. Defaults to CACHE_PERMANENT (optional).\n    'expire' => CACHE_TEMPORARY,\n    // Enable cache invalidation for entity based resources. Defaults to TRUE (optional).\n    'simpleInvalidate' => TRUE,\n    // Use a different cache backend for this resource. Defaults to variable_get('cache_default_class', 'DrupalDatabaseCache') (optional).\n    'class' => 'MemCacheDrupal',\n    // Account cache granularity. Instead of caching per user you can choose to cache per role. Default: DRUPAL_CACHE_PER_USER.\n    'granularity' => DRUPAL_CACHE_PER_ROLE,\n  ),\n);\n```\n\nAdditionally you can define a cache backend for a given cache bin by setting the\n variable `cache_class_<cache-bin-name>` to the class to be used. This way all\nthe resouces caching to that particular bin will use that cache backend instead\nof the default one.\n\n\n## Rate limit\nRESTful provides rate limit functionality out of the box. A rate limit is a way\nto protect your API service from flooding, basically consisting on checking is\nthe number of times an event has happened in a given period is greater that the\nmaximum allowed.\n\n\n### Rate limit events\nYou can define your own rate limit events for your resources and define the\nlimit an period for those, for that you only need to create a new _rate\\_limit_\nCTools plugin and implement the `isRequestedEvent` method. Every request the\n`isRequestedEvent` will be evaluated and if it returns true that request will\nincrease the number of hits -for that particular user- for that event. If the\nnumber of hits is bigger than the allowed limit an exception will be raised.\n\nTwo events are provided out of the box: the request event -that is always true\nfor every request- and the global event -that is always true and is not\ncontained for a given resource, all resources will increment the hit counter-.\n\nThis way, for instance, you could define different limit for read operations\nthan for write operations by checking the HTTP method in `isRequestedEvent`.\n\n\n### Configuring your rate limits\nYou can configure the declared Rate Limit events in every resource by providing\na configuration array. The following is taken from the example resource articles\n1.4 (articles\\_\\_1\\_4.inc):\n\n```php\n…\n  'rate_limit' => array(\n    // The 'request' event is the basic event. You can declare your own events.\n    'request' => array(\n      'event' => 'request',\n      // Rate limit is cleared every day.\n      'period' => new \\DateInterval('P1D'),\n      'limits' => array(\n        'authenticated user' => 3,\n        'anonymous user' => 2,\n        'administrator' => \\Drupal\\restful\\RateLimit\\RateLimitManager::UNLIMITED_RATE_LIMIT,\n      ),\n    ),\n  ),\n…\n```\n\nAs you can see in the example you can set the rate limit differently depending\non the role of the visiting user.\n\nSince the global event is not tied to any resource the limit and period is\nspecified by setting the following variables:\n  - `restful_global_rate_limit`: The number of allowed hits. This is global for\n    all roles.\n  - `restful_global_rate_period`: The period string compatible with\n    \\DateInterval.\n\n\n\n## Documenting your resources.\nA resource can be documented in the plugin definition using the `'label'`\nand `'description'` keys:\n\n```php\n$plugin = array(\n  // This is the human readable name of the resource.\n  'label' => t('User'),\n  // Use de description to provide more extended information about the resource.\n  'description' => t('Export the \"User\" entity.'),\n  'resource' => 'users',\n  'class' => 'RestfulEntityBaseUser',\n  ...\n);\n```\n\nThis should not include any information about the endpoints or the allowed HTTP\nmethods on them, since those will be accessed directly on the aforementioned\nendpoint. This information aims to describe what the accessed resource\nrepresents.\n\nTo access this information just use the `discovery` resource at the api\nhomepage:\n\n```shell\n# List resources\ncurl -u user:password https://example.org/api\n```\n"
  },
  {
    "path": "help/problem-instances-bad-request.html",
    "content": "<h2>Malformed syntax.</h2>\n  <p>The request could not be understood by the server due to malformed syntax.\n  </p>\n"
  },
  {
    "path": "help/problem-instances-flood.html",
    "content": "<h2>Rate limit exceeded.</h2>\n  <p>The user has sent too many requests in a given amount of time. Intended for\n    use with rate limiting schemes.</p>\n"
  },
  {
    "path": "help/problem-instances-forbidden.html",
    "content": "<h2>Forbidden resource access.</h2>\n  <p>The request was a valid request, but the server is refusing to respond to\n    it. Unlike a 401 Unauthorized response, authenticating will make no\n    difference.</p>\n"
  },
  {
    "path": "help/problem-instances-gone.html",
    "content": "<h2>Resource no longer available.</h2>\n  <p>Indicates that the resource requested is no longer available and will not\n    be available again. This should be used when a resource has been\n    intentionally removed and the resource should be purged. Upon receiving a\n    410 status code, the client should not request the resource again in the\n    future. Clients such as search engines should remove the resource from their\n    indices. Most use cases do not require clients and search engines to purge\n    the resource, and a \"404 Not Found\" may be used instead.</p>\n"
  },
  {
    "path": "help/problem-instances-incompatible-field-definition.html",
    "content": "<h2>Incompatible field definition.</h2>\n  <p>The field configuration contains incompatible or conflicting field definitions. Please make sure to read the\n      documentation on how to declare your resource fields.</p>\n"
  },
  {
    "path": "help/problem-instances-not-found.html",
    "content": "<h2>Document not found.</h2>\n  <p>The requested resource could not be found but may be available again in the\n    future. Subsequent requests by the client are permissible.</p>\n"
  },
  {
    "path": "help/problem-instances-not-implemented.html",
    "content": "<h2>Operation not supported.</h2>\n  <p>This error means that the operation you are attempting on the selected\n    resource is not implemented in the server. If you think this operation\n    should be supported, contact the support team.</p>\n"
  },
  {
    "path": "help/problem-instances-server-configuration.html",
    "content": "<h2>Server configuration error.</h2>\n  <p>Some configuration for the RESTful module is causing an unrecoverable\n    error. Please check your configuration.</p>\n"
  },
  {
    "path": "help/problem-instances-server-error.html",
    "content": "<h2>Internal server error exception.</h2>\n  <p>Generic exception thrown when there is an error in the server side.</p>\n"
  },
  {
    "path": "help/problem-instances-service-unavailable.html",
    "content": "<h2>Server is unavailable.</h2>\n  <p>The server is currently unavailable (because it is overloaded or down for\n    maintenance). Generally, this is a temporary state.</p>\n"
  },
  {
    "path": "help/problem-instances-unauthorized.html",
    "content": "<h2>Authentication needed.</h2>\n  <p>Similar to 403 Forbidden, but specifically for use when authentication is\n    required and has failed or has not yet been provided. The response must\n    include a WWW-Authenticate header field containing a challenge applicable to\n    the requested resource. See the authentication methods documentation for\n    more information.</p>\n"
  },
  {
    "path": "help/problem-instances-unprocessable-entity.html",
    "content": "<h2>Semantic error.</h2>\n  <p>The request was well-formed but was unable to be followed due to semantic\n    errors.</p>\n"
  },
  {
    "path": "help/problem-instances-unsupported-media-type.html",
    "content": "<h2>Type not supported by the server.</h2>\n  <p>The request entity has a media type which the server or resource does not\n    support. For example, the client uploads an image as image/svg+xml, but the\n    server requires that images use a different format.</p>\n"
  },
  {
    "path": "help/problem-instances.html",
    "content": "<h2>Index</h2>\n"
  },
  {
    "path": "help/readme.html",
    "content": "Go to the <a href=\"https://github.com/Gizra/restful\">project page</a> in GitHub.\n"
  },
  {
    "path": "help/restful.help.ini",
    "content": "[advanced help settings]\nline break = TRUE\n\n[readme]\ntitle = README\nweight = -10\n\n[problem-instances]\ntitle = RESTful problem instances\nweight = 0\n\n[problem-instances-bad-request]\ntitle = Bad Request\nweight = -90\nparent = problem-instances\n\n[problem-instances-flood]\ntitle = Flood\nweight = -80\nparent = problem-instances\n\n[problem-instances-forbidden]\ntitle = Bad Request\nweight = -70\nparent = problem-instances\n\n[problem-instances-gone]\ntitle = Gone\nweight = -60\nparent = problem-instances\n\n[problem-instances-service-unavailable]\ntitle = Service unavailable\nweight = -55\nparent = problem-instances\n\n[problem-instances-unauthorized]\ntitle = Unauthorized\nweight = -50\nparent = problem-instances\n\n[problem-instances-unprocessable-entity]\ntitle = Unprocessable entity\nweight = -40\nparent = problem-instances\n\n[problem-instances-unsupported-media-type]\ntitle = Unsupported media type\nweight = -30\nparent = problem-instances\n\n"
  },
  {
    "path": "modules/restful_example/restful_example.info",
    "content": "name = RESTful example\ndescription = Example module for the RESTful module.\ncore = 7.x\ndependencies[] = restful\n\nregistry_autoload[] = PSR-0\nregistry_autoload[] = PSR-4\n"
  },
  {
    "path": "modules/restful_example/restful_example.module",
    "content": "<?php\n\n/**\n * @file\n * Example module for the RESTful module.\n */\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/formatter/FormatterHalXml.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\FormatterHalJson.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\formatter;\n\nuse Drupal\\restful\\Plugin\\formatter\\FormatterHalJson;\nuse Drupal\\restful\\Plugin\\formatter\\FormatterInterface;\n\n/**\n * Class FormatterHalXml\n * @package Drupal\\restful\\Plugin\\formatter\n *\n * @Formatter(\n *   id = \"hal_xml\",\n *   label = \"HAL+XML\",\n *   description = \"Output in using the HAL conventions and XML format.\",\n *   curie = {\n *     \"name\": \"hal\",\n *     \"path\": \"doc/rels\",\n *     \"template\": \"/{rel}\",\n *   },\n * )\n */\nclass FormatterHalXml extends FormatterHalJson implements FormatterInterface {\n\n  /**\n   * Content Type\n   *\n   * @var string\n   */\n  protected $contentType = 'application/xml; charset=utf-8';\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(array $structured_data) {\n    return $this->arrayToXML($structured_data, new \\SimpleXMLElement('<api/>'))->asXML();\n  }\n\n  /**\n   * Converts the input array into an XML formatted string.\n   *\n   * @param array $data\n   *   The input array.\n   * @param \\SimpleXMLElement $xml\n   *   The object that will perform the conversion.\n   *\n   * @return \\SimpleXMLElement\n   */\n  protected function arrayToXML(array $data, \\SimpleXMLElement $xml) {\n    foreach ($data as $key => $value) {\n      if(is_array($value)) {\n        if(!is_numeric($key)){\n          $subnode = $xml->addChild(\"$key\");\n          $this->arrayToXML($value, $subnode);\n        }\n        else{\n          $subnode = $xml->addChild(\"item$key\");\n          $this->arrayToXML($value, $subnode);\n        }\n      }\n      else {\n        $xml->addChild(\"$key\", htmlspecialchars(\"$value\"));\n      }\n    }\n    return $xml;\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/Tags__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\Tags__1_0.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Tags\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"tags:1.0\",\n *   resource = \"tags\",\n *   label = \"Tags\",\n *   description = \"Export the tags taxonomy term.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"taxonomy_term\",\n *     \"bundles\": {\n *       \"tags\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Tags__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::checkEntityAccess().\n   *\n   * Allow access to create \"Tags\" resource for privileged users, as\n   * we can't use entity_access() since entity_metadata_taxonomy_access()\n   * denies it for a non-admin user.\n   */\n  protected function checkEntityAccess($op, $entity_type, $entity) {\n    $account = $this->getAccount();\n    return user_access('create article content', $account);\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/comment/Comments__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\comment\\Comments__1_0.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\comment;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Comments__1_0\n * @package Drupal\\restful_example\\Plugin\\resource\\comment\n *\n * @Resource(\n *   name = \"comments:1.0\",\n *   resource = \"comments\",\n *   label = \"Comments\",\n *   description = \"Export the comments with all authentication providers.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"comment\",\n *     \"bundles\": FALSE,\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Comments__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['nid'] = array(\n      'property' => 'node',\n      'sub_property' => 'nid',\n    );\n\n    // Add a custom field for test only.\n    if (field_info_field('comment_text')) {\n      $public_fields['comment_text'] = array(\n        'property' => 'comment_text',\n        'sub_property' => 'value',\n      );\n    }\n\n    return $public_fields;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function dataProviderClassName() {\n    return '\\Drupal\\restful_example\\Plugin\\resource\\comment\\DataProviderComment';\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/comment/DataProviderComment.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\comment\\DataProviderComment.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\comment;\n\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntity;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\n\nclass DataProviderComment  extends DataProviderEntity implements DataProviderInterface {\n\n  /**\n   * Overrides DataProviderEntity::setPropertyValues().\n   *\n   * Set nid and node type to a comment.\n   *\n   * Note that to create a comment with 'post comments' permission, apply a\n   * patch on https://www.drupal.org/node/2236229\n   */\n  protected function setPropertyValues(\\EntityDrupalWrapper $wrapper, $object, $replace = FALSE) {\n    $comment = $wrapper->value();\n    if (empty($comment->nid) && !empty($object['nid'])) {\n      // Comment nid must be set manually, as the nid property setter requires\n      // 'administer comments' permission.\n      $comment->nid = $object['nid'];\n      unset($object['nid']);\n\n      // Make sure we have a bundle name.\n      $node = node_load($comment->nid);\n      $comment->node_type = 'comment_node_' . $node->type;\n    }\n\n    parent::setPropertyValues($wrapper, $object, $replace);\n  }\n\n  /**\n   * Overrides DataProviderEntity::getQueryForList().\n   *\n   * Expose only published comments.\n   */\n  public function getQueryForList() {\n    $query = parent::getQueryForList();\n    $query->propertyCondition('status', COMMENT_PUBLISHED);\n    return $query;\n  }\n\n  /**\n   * Overrides DataProviderEntity::getQueryCount().\n   *\n   * Only count published comments.\n   */\n  public function getQueryCount() {\n    $query = parent::getQueryCount();\n    $query->propertyCondition('status', COMMENT_PUBLISHED);\n    return $query;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function entityPreSave(\\EntityDrupalWrapper $wrapper) {\n    $comment = $wrapper->value();\n    if (!empty($comment->cid)) {\n      // Comment is already saved.\n      return;\n    }\n\n    $comment->uid = $this->getAccount()->uid;\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v1/Articles__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_0.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.0\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the articles with all authentication providers.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Articles__1_0 extends ResourceNode implements ResourceInterface {}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v1/Articles__1_1.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_1.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Articles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.1\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 1\n * )\n */\nclass Articles__1_1 extends Articles__1_0 implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n    unset($public_fields['self']);\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v1/Articles__1_4.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_4.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\nuse Drupal\\restful\\RateLimit\\RateLimitManager;\n\n/**\n * Class Articles__1_4\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.4\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the articles with all authentication providers.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 4\n * )\n */\nclass Articles__1_4 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * Constructs an Articles__1_4 object.\n   *\n   * @param array $configuration\n   *   A configuration array containing information about the plugin instance.\n   * @param string $plugin_id\n   *   The plugin_id for the plugin instance.\n   * @param mixed $plugin_definition\n   *   The plugin implementation definition.\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n    $this->pluginDefinition['rateLimit'] = array(\n      // The 'request' event is the basic event. You can declare your own\n      // events.\n      'request' => array(\n        'event' => 'request',\n        // Rate limit is cleared every day.\n        'period' => 'P1D',\n        'limits' => array(\n          'authenticated user' => 3,\n          'anonymous user' => 2,\n          'administrator' => RateLimitManager::UNLIMITED_RATE_LIMIT,\n        ),\n      ),\n    );\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v1/Articles__1_5.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_5.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles__1_5\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.5\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the articles with all authentication providers.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 5\n * )\n */\nclass Articles__1_5 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * Overrides ResourceNode::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['body'] = array(\n      'property' => 'body',\n      'sub_property' => 'value',\n    );\n\n    $public_fields['tags'] = array(\n      'property' => 'field_tags',\n      'resource' => array(\n        'name' => 'tags',\n        'majorVersion' => 1,\n        'minorVersion' => 0,\n      ),\n    );\n\n    $public_fields['image'] = array(\n      'property' => 'field_image',\n      'process_callbacks' => array(\n        array($this, 'imageProcess'),\n      ),\n      'image_styles' => array('thumbnail', 'medium', 'large'),\n    );\n\n    // By checking that the field exists, we allow re-using this class on\n    // different tests, where different fields exist.\n    if (field_info_field('field_images')) {\n      $public_fields['images'] = array(\n        'property' => 'field_images',\n        'process_callbacks' => array(\n          array($this, 'imageProcess'),\n        ),\n        'image_styles' => array('thumbnail', 'medium', 'large'),\n      );\n    }\n\n    $public_fields['user'] = array(\n      'property' => 'author',\n      'resource' => array(\n        // The name of the resource to map to.\n        'name' => 'users',\n        // Determines if the entire resource should appear, or only the ID.\n        'fullView' => TRUE,\n        'majorVersion' => 1,\n        'minorVersion' => 0,\n      ),\n    );\n\n    $public_fields['static'] = array(\n      'callback' => '\\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_5::randomNumber',\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * Process callback, Remove Drupal specific items from the image array.\n   *\n   * @param array $value\n   *   The image array.\n   *\n   * @return array\n   *   A cleaned image array.\n   */\n  public function imageProcess($value) {\n    if (ResourceFieldBase::isArrayNumeric($value)) {\n      $output = array();\n      foreach ($value as $item) {\n        $output[] = $this->imageProcess($item);\n      }\n      return $output;\n    }\n    return array(\n      'id' => $value['fid'],\n      'self' => file_create_url($value['uri']),\n      'filemime' => $value['filemime'],\n      'filesize' => $value['filesize'],\n      'width' => $value['width'],\n      'height' => $value['height'],\n      'styles' => $value['image_styles'],\n    );\n  }\n\n  /**\n   * Callback, Generate a random number.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter containing the wrapper.\n   *\n   * @return int\n   *   A random integer.\n   */\n  public static function randomNumber(DataInterpreterInterface $interpreter) {\n    return mt_rand();\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v1/Articles__1_6.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_6.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles__1_6\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.6\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the articles with all authentication providers.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   formatter = \"hal_xml\",\n *   majorVersion = 1,\n *   minorVersion = 6\n * )\n */\nclass Articles__1_6 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * Overrides ResourceNode::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['body'] = array(\n      'property' => 'body',\n      'sub_property' => 'value',\n    );\n\n    return $public_fields;\n  }\n\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v1/Articles__1_7.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_7.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles__1_7\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.7\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the article content type using view modes.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *     \"viewMode\" = {\n *       \"name\": \"default\",\n *       \"fieldMap\": {\n *         \"body\": \"body\",\n *         \"field_tags\": \"tags\",\n *         \"field_image\": \"image\",\n *       }\n *     }\n *   },\n *   majorVersion = 1,\n *   minorVersion = 7\n * )\n */\nclass Articles__1_7 extends ResourceNode implements ResourceInterface {}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v2/Articles__2_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v2\\Articles__2_0.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v2;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:2.0\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 2,\n *   minorVersion = 0\n * )\n */\nclass Articles__2_0 extends ResourceNode implements ResourceInterface {}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/node/article/v2/Articles__2_1.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v2\\Articles__2_1.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\node\\article\\v2;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:2.1\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *     \"idField\": \"custom-uuid\"\n *   },\n *   formatter = \"json_api\",\n *   majorVersion = 2,\n *   minorVersion = 1\n * )\n */\nclass Articles__2_1 extends ResourceNode implements ResourceInterface {\n\n  // TODO: Document the use of the idField.\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $fields = parent::publicFields();\n\n    $fields['custom-uuid'] = array(\n      'methods' => array(),\n      'property' => 'uuid',\n    );\n\n    return $fields;\n  }\n\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/variables/DataInterpreterVariable.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\variables\\DataInterpreterVariable.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\variables;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterBase;\n\nclass DataInterpreterVariable extends DataInterpreterBase {}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/variables/DataProviderVariable.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\variables\\DataProviderVariable.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\variables;\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\ArrayWrapper;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProvider;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\n\n/**\n * Class DataProviderVariable.\n *\n * @package Drupal\\restful_example\\Plugin\\resource\\variables\n */\nclass DataProviderVariable extends DataProvider implements DataProviderInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path = NULL, array $options = array(), $langcode = NULL) {\n    parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);\n    if (empty($this->options['urlParams'])) {\n      $this->options['urlParams'] = array(\n        'filter' => TRUE,\n        'sort' => TRUE,\n        'fields' => TRUE,\n      );\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return count($this->getIndexIds());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    // Overly simplified update method. Search for the name and value fields,\n    // and set the variable.\n    $name_key = $this->searchPublicFieldByProperty('name');\n    $value_key = $this->searchPublicFieldByProperty('value');\n    if (empty($object[$name_key]) || empty($object[$value_key])) {\n      throw new BadRequestException('You need to provide the variable name and value.');\n    }\n    $identifier = $object[$name_key];\n    if (!empty($GLOBALS['conf'][$identifier])) {\n      throw new UnprocessableEntityException('The selected variable already exists.');\n    }\n    variable_set($identifier, $object[$value_key]);\n    return array($this->view($identifier));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    $resource_field_collection = $this->initResourceFieldCollection($identifier);\n\n    $input = $this->getRequest()->getParsedInput();\n    $limit_fields = !empty($input['fields']) ? explode(',', $input['fields']) : array();\n\n    foreach ($this->fieldDefinitions as $resource_field_name => $resource_field) {\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface $resource_field */\n\n      if ($limit_fields && !in_array($resource_field_name, $limit_fields)) {\n        // Limit fields doesn't include this property.\n        continue;\n      }\n\n      if (!$this->methodAccess($resource_field) || !$resource_field->access('view', $resource_field_collection->getInterpreter())) {\n        // The field does not apply to the current method or has denied\n        // access.\n        continue;\n      }\n\n      $resource_field_collection->set($resource_field->id(), $resource_field);\n    }\n    return $resource_field_collection;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    $return = array();\n    foreach ($identifiers as $identifier) {\n      try {\n        $row = $this->view($identifier);\n      }\n      catch (InaccessibleRecordException $e) {\n        $row = NULL;\n      }\n      $return[] = $row;\n    }\n\n    return array_values(array_filter($return));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    // Overly simplified update method. Search for the name and value fields,\n    // and set the variable.\n    $name_key = $this->searchPublicFieldByProperty('name');\n    $value_key = $this->searchPublicFieldByProperty('value');\n    if (empty($object[$value_key])) {\n      if (!$replace) {\n        return array($this->view($identifier));\n      }\n      $object[$value_key] = NULL;\n    }\n    if (!empty($object[$name_key]) && $object[$name_key] != $identifier) {\n      // If the variable name is changed, then remove the old one.\n      $this->remove($identifier);\n      $identifier = $object[$name_key];\n    }\n    variable_set($identifier, $object[$value_key]);\n    return array($this->view($identifier));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    variable_del($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    $output = array();\n    foreach ($GLOBALS['conf'] as $key => $value) {\n      $output[] = array('name' => $key, 'value' => $value);\n    }\n    // Apply filters.\n    $output = $this->applyFilters($output);\n    $output = $this->applySort($output);\n    return array_map(function ($item) { return $item['name']; }, $output);\n  }\n\n  /**\n   * Removes plugins from the list based on the request options.\n   *\n   * @param \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[] $variables\n   *   The array of resource plugins keyed by instance ID.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[]\n   *   The same array minus the filtered plugins.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\ServiceUnavailableException\n   */\n  protected function applyFilters(array $variables) {\n    $filters = $this->parseRequestForListFilter();\n\n    // Apply the filter to the list of plugins.\n    foreach ($variables as $delta => $variable) {\n      $variable_name = $variable['name'];\n      // A filter on a result needs the ResourceFieldCollection representing the\n      // result to return.\n      $interpreter = $this->initDataInterpreter($variable_name);\n      $this->fieldDefinitions->setInterpreter($interpreter);\n      foreach ($filters as $filter) {\n        if (!$this->fieldDefinitions->evalFilter($filter)) {\n          unset($variables[$delta]);\n        }\n      }\n    }\n    $this->fieldDefinitions->setInterpreter(NULL);\n    return $variables;\n  }\n\n  /**\n   * Sorts plugins on the list based on the request options.\n   *\n   * @param \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[] $variables\n   *   The array of resource plugins keyed by instance ID.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[]\n   *   The sorted array.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\ServiceUnavailableException\n   */\n  protected function applySort(array $variables) {\n    if ($sorts = $this->parseRequestForListSort()) {\n      uasort($variables, function ($variable1, $variable2) use ($sorts) {\n        $interpreter1 = $this->initDataInterpreter($variable1['name']);\n        $interpreter2 = $this->initDataInterpreter($variable2['name']);\n        foreach ($sorts as $key => $order) {\n          $property = $this->fieldDefinitions->get($key)->getProperty();\n          $value1 = $interpreter1->getWrapper()->get($property);\n          $value2 = $interpreter2->getWrapper()->get($property);\n          if ($value1 == $value2) {\n            continue;\n          }\n\n          return ($order == 'DESC' ? -1 : 1) * strcmp($value1, $value2);\n        }\n\n        return 0;\n      });\n    }\n    return $variables;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function initDataInterpreter($identifier) {\n    return new DataInterpreterVariable($this->getAccount(), new ArrayWrapper(array(\n      'name' => $identifier,\n      'value' => variable_get($identifier),\n    )));\n  }\n\n  /**\n   * Finds the public field name that has the provided property.\n   *\n   * @param string $property\n   *   The property to find.\n   *\n   * @return string\n   *   The name of the public name.\n   */\n  protected function searchPublicFieldByProperty($property) {\n    foreach ($this->fieldDefinitions as $public_name => $resource_field) {\n      if ($resource_field->getProperty() == $property) {\n        return $public_name;\n      }\n    }\n    return NULL;\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/variables/DataProviderVariableInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\variables\\DataProviderVariableInterface.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\variables;\n\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\n\ninterface DataProviderVariableInterface extends DataProviderInterface {}\n"
  },
  {
    "path": "modules/restful_example/src/Plugin/resource/variables/Variables__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_example\\Plugin\\resource\\variables\\Variables__1_0.\n */\n\nnamespace Drupal\\restful_example\\Plugin\\resource\\variables;\n\nuse Drupal\\restful\\Plugin\\resource\\Resource;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Variables\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"variables:1.0\",\n *   resource = \"variables\",\n *   label = \"Variables\",\n *   description = \"Export the variables.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"idField\": \"variable_name\"\n *   },\n *   renderCache = {\n *     \"render\": true\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Variables__1_0 extends Resource implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    return array(\n      'variable_name' => array('property' => 'name'),\n      'variable_value' => array('property' => 'value'),\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function dataProviderClassName() {\n    return '\\Drupal\\restful_example\\Plugin\\resource\\variables\\DataProviderVariable';\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_token_auth/modules/restful_token_auth_test/restful_token_auth_test.info",
    "content": "name = RESTful Token Authentication tests\ndescription = Test module that provides some example resources.\ncore = 7.x\n\ndependencies[] = restful_token_auth\n\nregistry_autoload[] = PSR-0\nregistry_autoload[] = PSR-4\n"
  },
  {
    "path": "modules/restful_token_auth/modules/restful_token_auth_test/restful_token_auth_test.module",
    "content": "<?php\n\n/**\n * @file\n * Module implementation file.\n */\n"
  },
  {
    "path": "modules/restful_token_auth/modules/restful_token_auth_test/src/Plugin/resource/Articles__1_3.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_token_auth_test\\Plugin\\resource\\Articles__1_3.\n */\n\nnamespace Drupal\\restful_token_auth_test\\Plugin\\resource;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class Articles__1_3\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"articles:1.3\",\n *   resource = \"articles\",\n *   label = \"Articles\",\n *   description = \"Export the articles with all authentication providers.\",\n *   authenticationTypes = {\n *     \"token\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 3\n * )\n */\nclass Articles__1_3 extends ResourceNode implements ResourceInterface {}\n"
  },
  {
    "path": "modules/restful_token_auth/restful_token_auth.admin.inc",
    "content": "<?php\n\n/**\n * Menu callback; Admin settings form.\n */\nfunction restful_token_auth_admin_settings($form, &$form_state) {\n  $form['restful_token_auth_delete_expired_tokens'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Delete expired tokens.'),\n    '#description' => t('Enable to delete expired tokens when trying to use an expired token and during cron runs.'),\n    '#default_value' => variable_get('restful_token_auth_delete_expired_tokens', TRUE),\n  );\n  $form['advanced'] = array(\n    '#type' => 'fieldset',\n    '#title' => t('Advanced'),\n    '#description' => t('Advanced configuration for the token authentication.'),\n    '#collapsible' => TRUE,\n    '#collapsed' => TRUE,\n  );\n  $form['advanced']['restful_token_auth_expiration_period'] = array(\n    '#type' => 'textfield',\n    '#title' => t('Expiration time'),\n    '#description' => t('The period string compatible with <a href=\"@url\">\\DateInterval</a>.', array('@url' => 'http://php.net/manual/en/class.dateinterval.php')),\n    '#default_value' => variable_get('restful_token_auth_expiration_period', 'P1D'),\n    '#element_validate' => array('restful_date_time_format_element_validate'),\n  );\n\n  return system_settings_form($form);\n}\n"
  },
  {
    "path": "modules/restful_token_auth/restful_token_auth.info",
    "content": "name = RESTful token authentication\ndescription = Authenticate a REST call using a token.\ncore = 7.x\ndependencies[] = restful\ndependencies[] = entityreference\nconfigure = admin/config/services/restful/token-auth\n\nregistry_autoload[] = PSR-0\nregistry_autoload[] = PSR-4\n\nfiles[] = tests/RestfulTokenAuthenticationTestCase.test\n"
  },
  {
    "path": "modules/restful_token_auth/restful_token_auth.install",
    "content": "<?php\n\n/**\n * @file\n * Install, update, and uninstall functions for the RESTful token authentication\n * module.\n */\n\n/**\n * Implements hook_schema().\n */\nfunction restful_token_auth_schema() {\n  $schema = array();\n  $schema['restful_token_auth'] = array(\n    'description' => 'The authentication token table.',\n    'fields' => array(\n      'id' => array(\n        'description' => 'The authentication token unique ID.',\n        'type' => 'serial',\n        'unsigned' => TRUE,\n        'not null' => TRUE,\n      ),\n      'type' => array(\n        'description' => 'The authentication token type.',\n        'type' => 'varchar',\n        'length' => 255,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'uid' => array(\n        'description' => 'The user the authentication token belongs to.',\n        'type' => 'int',\n        'not null' => TRUE,\n        'default' => 0,\n      ),\n      'name' => array(\n        'description' => 'The authentication token name.',\n        'type' => 'varchar',\n        'length' => 255,\n        'not null' => FALSE,\n        'default' => '',\n      ),\n      'token' => array(\n        'description' => 'The authentication token security token.',\n        'type' => 'varchar',\n        'length' => 255,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'created' => array(\n        'description' => 'The Unix timestamp when the authentication token was created.',\n        'type' => 'int',\n        'not null' => TRUE,\n        'default' => 0,\n      ),\n      'expire' => array(\n        'description' => 'The Unix timestamp when the authentication token will expire.',\n        'type' => 'int',\n        'not null' => FALSE,\n        'default' => NULL,\n      ),\n    ),\n    'foreign keys' => array(\n      'uid' => array(\n        'table' => 'users',\n        'columns' => array('uid' => 'uid'),\n      ),\n    ),\n    'primary key' => array('id'),\n  );\n\n  // Cache bins for Entity-cache module.\n  $cache_schema = drupal_get_schema_unprocessed('system', 'cache');\n  $types = array('restful_token_auth');\n\n  foreach ($types as $type) {\n    $schema[\"cache_entity_$type\"] = $cache_schema;\n    $schema[\"cache_entity_$type\"]['description'] = \"Cache table used to store $type entity records.\";\n  }\n\n  return $schema;\n}\n\n/**\n * Implements hook_install().\n */\nfunction restful_token_auth_install() {\n  restful_token_auth_create_field_refresh_token();\n}\n\n/**\n * Implements hook_uninstall().\n */\nfunction restful_token_auth_uninstall() {\n  variable_del('restful_token_auth_delete_expired_tokens');\n  field_delete_field('refresh_token_reference');\n}\n\n/**\n * Adds the refresh token entity reference.\n */\nfunction restful_token_auth_update_7100(&$sandbox) {\n  // Change the type column for existing tokens.\n  db_update('restful_token_auth')\n    ->fields(array(\n      'type' => 'access_token',\n    ))\n    ->execute();\n\n  // Attach the new field.\n  restful_token_auth_create_field_refresh_token();\n}\n\n/**\n * Helper function to create the refresh token entity reference.\n */\nfunction restful_token_auth_create_field_refresh_token() {\n  // Add an entity reference field to the access_token bundle to link to the\n  // corresponding refresh token.\n  $field_name = 'refresh_token_reference';\n  $field = array(\n    'entity_types' => array('restful_token_auth'),\n    'settings' => array(\n      'handler' => 'base',\n      'target_type' => 'restful_token_auth',\n      'handler_settings' => array(\n        'target_bundles' => array(\n          'refresh_token' => 'refresh_token',\n        ),\n      ),\n    ),\n    'field_name' => $field_name,\n    'type' => 'entityreference',\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => $field_name,\n    'bundle' => 'access_token',\n    'entity_type' => 'restful_token_auth',\n    'label' => t('Refresh token'),\n    'description' => t('Token used to get a new access token once it is expired.'),\n    'required' => FALSE,\n  );\n  field_create_instance($instance);\n}\n"
  },
  {
    "path": "modules/restful_token_auth/restful_token_auth.module",
    "content": "<?php\n\n/**\n * @file\n * RESTful token authentication.\n */\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Authentication\\AuthenticationManager;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Implements hook_menu().\n */\nfunction restful_token_auth_menu() {\n  // Add administration page.\n  $items['admin/config/services/restful/token-auth'] = array(\n    'title' => 'Token Authentication',\n    'description' => 'Administer the RESTful Token Authentication module.',\n    'type' => MENU_LOCAL_TASK,\n    'page callback' => 'drupal_get_form',\n    'page arguments' => array('restful_token_auth_admin_settings'),\n    'access arguments' => array('administer restful'),\n    'file' => 'restful_token_auth.admin.inc',\n  );\n  return $items;\n}\n\n/**\n * Implements hook_restful_parse_request_alter().\n */\nfunction restful_token_auth_restful_parse_request_alter(RequestInterface &$request) {\n  // In this hook we cannot rely on the service to be ready.\n  $authentication_manager = new AuthenticationManager();\n  try {\n    // If the the authentication provider have not been added yet, add it.\n    $authentication_manager->addAuthenticationProvider('token');\n    $plugin = $authentication_manager->getPlugin('token');\n  }\n  catch (PluginNotFoundException $e) {\n    watchdog_exception('restful_token_auth', $e);\n    return;\n  }\n  $plugin_definition = $plugin->getPluginDefinition();\n  $param_name = $plugin_definition['options']['paramName'];\n\n  $header = $request->getHeaders()->get($param_name);\n  $request->setApplicationData($param_name, $header->getValueString());\n}\n\n/**\n * Implements hook_entity_info().\n */\nfunction restful_token_auth_entity_info() {\n  $items['restful_token_auth'] = array(\n    'label' => t('Authentication token'),\n    'entity class' => '\\\\Drupal\\\\restful_token_auth\\\\Entity\\\\RestfulTokenAuth',\n    'controller class' => '\\\\Drupal\\\\restful_token_auth\\\\Entity\\\\RestfulTokenAuthController',\n    'base table' => 'restful_token_auth',\n    'fieldable' => TRUE,\n    'entity keys' => array(\n      'id' => 'id',\n      'label' => 'name',\n      'bundle' => 'type',\n    ),\n    'bundles' => array(\n      'access_token' => array(\n        'label' => t('Access token'),\n      ),\n      'refresh_token' => array(\n        'label' => t('Refresh token'),\n      ),\n    ),\n    'bundle keys' => array(\n      'bundle' => 'type',\n    ),\n    'module' => 'restful_token_auth',\n    'entity cache' => module_exists('entitycache'),\n  );\n\n  return $items;\n}\n\n/**\n * Implements hook_cron().\n *\n * Delete expired token auth entities.\n */\nfunction restful_token_auth_cron() {\n  if (!variable_get('restful_token_auth_delete_expired_tokens', TRUE)) {\n    // We should not delete expired tokens.\n    return;\n  }\n\n  $query = new \\EntityFieldQuery();\n  $result = $query\n    ->entityCondition('entity_type', 'restful_token_auth')\n    ->propertyCondition('expire', REQUEST_TIME, '<')\n    ->range(0, 50)\n    ->execute();\n\n  if (empty($result['restful_token_auth'])) {\n    // No expired tokens.\n    return;\n  }\n\n  $ids = array_keys($result['restful_token_auth']);\n  entity_delete_multiple('restful_token_auth', $ids);\n}\n\n/**\n * Implements hook_restful_resource_alter().\n */\nfunction restful_token_auth_restful_resource_alter(ResourceInterface &$resource) {\n  $plugin_definition = $resource->getPluginDefinition();\n  if (\n    empty($plugin_definition['dataProvider']['entityType']) ||\n    $plugin_definition['dataProvider']['entityType'] != 'restful_token_auth' ||\n    !empty($plugin_definition['formatter'])\n  ) {\n    return;\n  }\n  // If this resource is based on access token entities and does not have an\n  // explicit formatter attached to it, then use the single_json formatter.\n  $plugin_definition['formatter'] = 'single_json';\n  $resource->setPluginDefinition($plugin_definition);\n}\n\n/**\n * Implements hook_user_update().\n */\nfunction restful_token_auth_user_update(&$edit, $account, $category) {\n  if ($edit['status']) {\n    return;\n  }\n\n  $query = new EntityFieldQuery();\n  $result = $query\n    ->entityCondition('entity_type', 'restful_token_auth')\n    ->propertyCondition('uid', $account->uid)\n    ->execute();\n\n  if (empty($result['restful_token_auth'])) {\n      return;\n  }\n\n  entity_delete_multiple('restful_token_auth', array_keys($result['restful_token_auth']));\n}\n"
  },
  {
    "path": "modules/restful_token_auth/src/Entity/RestfulTokenAuth.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful_token_auth\\Entity\\RestfulTokenAuth.\n */\n\nnamespace Drupal\\restful_token_auth\\Entity;\n\nclass RestfulTokenAuth extends \\Entity {}\n"
  },
  {
    "path": "modules/restful_token_auth/src/Entity/RestfulTokenAuthController.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful_token_auth\\Entity\\RestfulTokenAuthController.\n */\n\nnamespace Drupal\\restful_token_auth\\Entity;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\n\nclass RestfulTokenAuthController extends \\EntityAPIController {\n\n  /**\n   * Create a new access_token entity with a referenced refresh_token.\n   *\n   * @param int $uid\n   *   The user ID.\n   *\n   * @return RestfulTokenAuth\n   *   The created entity.\n   */\n  public function generateAccessToken($uid) {\n    $refresh_token = $this->generateRefreshToken($uid);\n    // Create a new access token.\n    $values = array(\n      'uid' => $uid,\n      'type' => 'access_token',\n      'created' => REQUEST_TIME,\n      'name' => t('Access token for: @uid', array(\n        '@uid' => $uid,\n      )),\n      'token' => drupal_random_key(),\n      'expire' => $this->getExpireTime(),\n      'refresh_token_reference' => array(\n        LANGUAGE_NONE => array(array(\n          'target_id' => $refresh_token->id,\n        )),\n      ),\n    );\n    $access_token = $this->create($values);\n    $this->save($access_token);\n\n    return $access_token;\n  }\n\n  /**\n   * Create a refresh token for the current user.\n   *\n   * It will delete all the existing refresh tokens for that same user as well.\n   *\n   * @param int $uid\n   *   The user ID.\n   *\n   * @return RestfulTokenAuth\n   *   The token entity.\n   */\n  private function generateRefreshToken($uid) {\n    // Check if there are other refresh tokens for the user.\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', 'restful_token_auth')\n      ->entityCondition('bundle', 'refresh_token')\n      ->propertyCondition('uid', $uid)\n      ->execute();\n\n    if (!empty($results['restful_token_auth'])) {\n      // Delete the tokens.\n      entity_delete_multiple('restful_token_auth', array_keys($results['restful_token_auth']));\n    }\n\n    // Create a new refresh token.\n    $values = array(\n      'uid' => $uid,\n      'type' => 'refresh_token',\n      'created' => REQUEST_TIME,\n      'name' => t('Refresh token for: @uid', array(\n        '@uid' => $uid,\n      )),\n      'token' => drupal_random_key(),\n    );\n    $refresh_token = $this->create($values);\n    $this->save($refresh_token);\n    return $refresh_token;\n  }\n\n  /**\n   * Return the expiration time.\n   *\n   * @throws ServerConfigurationException\n   *\n   * @return int\n   *   Timestamp with the expiration time.\n   */\n  protected function getExpireTime() {\n    $now = new \\DateTime();\n    try {\n      $expiration = $now->add(new \\DateInterval(variable_get('restful_token_auth_expiration_period', 'P1D')));\n    }\n    catch (\\Exception $e) {\n      throw new ServerConfigurationException('Invalid DateInterval format provided.');\n    }\n    return $expiration->format('U');\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_token_auth/src/Plugin/authentication/TokenAuthentication.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_token_auth\\Plugin\\authentication\\TokenAuthentication\n */\n\nnamespace Drupal\\restful_token_auth\\Plugin\\authentication;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\authentication\\Authentication;\n\n/**\n * Class TokenAuthentication\n * @package Drupal\\restful\\Plugin\\authentication\n *\n * @Authentication(\n *   id = \"token\",\n *   label = \"Token based authentication\",\n *   description = \"Authenticate requests based on the token sent in the request.\",\n *   options = {\n *     \"paramName\" = \"access_token\",\n *   },\n * )\n */\nclass TokenAuthentication extends Authentication {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function applies(RequestInterface $request) {\n    return (bool) $this->extractToken($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function authenticate(RequestInterface $request) {\n    // Access token may be on the request, or in the headers.\n    if (!$token = $this->extractToken($request)) {\n      return NULL;\n    }\n\n    // Check if there is a token that has not expired yet.\n    $query = new \\EntityFieldQuery();\n    $result = $query\n      ->entityCondition('entity_type', 'restful_token_auth')\n      ->entityCondition('bundle', 'access_token')\n      ->propertyCondition('token', $token)\n      ->range(0, 1)\n      ->execute();\n\n\n    if (empty($result['restful_token_auth'])) {\n      // No token exists.\n      return NULL;\n    }\n\n    $id = key($result['restful_token_auth']);\n    $auth_token = entity_load_single('restful_token_auth', $id);\n\n    if (!empty($auth_token->expire) && $auth_token->expire < REQUEST_TIME) {\n      // Token is expired.\n\n      if (variable_get('restful_token_auth_delete_expired_tokens', TRUE)) {\n        // Token has expired, so we can delete this token.\n        $auth_token->delete();\n      }\n\n      return NULL;\n    }\n\n    return user_load($auth_token->uid);\n  }\n\n  /**\n   * Extract the token from the request.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   *\n   * @return string\n   *   The extracted token.\n   */\n  protected function extractToken(RequestInterface $request) {\n    $plugin_definition = $this->getPluginDefinition();\n    $options = $plugin_definition['options'];\n    $key_name = !empty($options['paramName']) ? $options['paramName'] : 'access_token';\n\n    // Access token may be on the request, or in the headers.\n    $input = $request->getParsedInput();\n\n    // If we don't have a $key_name on either the URL or the in the headers,\n    // then check again using a hyphen instead of an underscore. This is due to\n    // new versions of Apache not accepting headers with underscores.\n    if (empty($input[$key_name]) && !$request->getHeaders()->get($key_name)->getValueString()) {\n      $key_name = str_replace('_', '-', $key_name);\n    }\n\n    return empty($input[$key_name]) ? $request->getHeaders()->get($key_name)->getValueString() : $input[$key_name];\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_token_auth/src/Plugin/resource/AccessToken__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful_token_auth\\Plugin\\resource\\AccessToken__1_0.\n */\n\nnamespace Drupal\\restful_token_auth\\Plugin\\resource;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntityInterface;\n\n/**\n * Class AccessToken__1_0\n * @package Drupal\\restful_token_auth\\Plugin\\resource\n *\n * @Resource(\n *   name = \"access_token:1.0\",\n *   resource = \"access_token\",\n *   label = \"Access token authentication\",\n *   description = \"Export the access token authentication resource.\",\n *   authenticationTypes = {\n *     \"cookie\",\n *     \"basic_auth\"\n *   },\n *   authenticationOptional = FALSE,\n *   dataProvider = {\n *     \"entityType\": \"restful_token_auth\",\n *     \"bundles\": {\n *       \"access_token\"\n *     },\n *   },\n *   formatter = \"single_json\",\n *   menuItem = \"login-token\",\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass AccessToken__1_0 extends TokenAuthenticationBase implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function controllersInfo() {\n    return array(\n      '' => array(\n        // Get or create a new token.\n        RequestInterface::METHOD_GET => 'getOrCreateToken',\n        RequestInterface::METHOD_OPTIONS => 'discover',\n      ),\n    );\n  }\n\n  /**\n   * Create a token for a user, and return its value.\n   */\n  public function getOrCreateToken() {\n    $entity_type = $this->getEntityType();\n    $account = $this->getAccount();\n    // Check if there is a token that did not expire yet.\n    /* @var DataProviderEntityInterface $data_provider */\n    $data_provider = $this->getDataProvider();\n    $query = $data_provider->EFQObject();\n    $result = $query\n      ->entityCondition('entity_type', $entity_type)\n      ->entityCondition('bundle', 'access_token')\n      ->propertyCondition('uid', $account->uid)\n      ->range(0, 1)\n      ->execute();\n\n    $token_exists = FALSE;\n\n    if (!empty($result[$entity_type])) {\n      $id = key($result[$entity_type]);\n      $access_token = entity_load_single($entity_type, $id);\n\n      $token_exists = TRUE;\n      if (!empty($access_token->expire) && $access_token->expire < REQUEST_TIME) {\n        if (variable_get('restful_token_auth_delete_expired_tokens', TRUE)) {\n          // Token has expired, so we can delete this token.\n          $access_token->delete();\n        }\n\n        $token_exists = FALSE;\n      }\n    }\n\n    if (!$token_exists) {\n      /* @var \\Drupal\\restful_token_auth\\Entity\\RestfulTokenAuthController $controller */\n      $controller = entity_get_controller($this->getEntityType());\n      $access_token = $controller->generateAccessToken($account->uid);\n      $id = $access_token->id;\n    }\n    $output = $this->view($id);\n\n    return $output;\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_token_auth/src/Plugin/resource/RefreshToken__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful_token_auth\\Plugin\\resource\\RefreshToken__1_0.\n */\n\nnamespace Drupal\\restful_token_auth\\Plugin\\resource;\n\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Util\\EntityFieldQuery;\nuse Drupal\\restful_token_auth\\Entity\\RestfulTokenAuth;\n\n/**\n * Class RefreshToken__1_0\n * @package Drupal\\restful_token_auth\\Plugin\\resource\n *\n * @Resource(\n *   name = \"refresh_token:1.0\",\n *   resource = \"refresh_token\",\n *   label = \"Refresh token authentication\",\n *   description = \"Export the refresh token authentication resource.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"restful_token_auth\",\n *     \"bundles\": {\n *       \"access_token\"\n *     },\n *   },\n *   formatter = \"single_json\",\n *   menuItem = \"refresh-token\",\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass RefreshToken__1_0 extends TokenAuthenticationBase implements ResourceInterface {\n\n  /**\n   * Overrides \\RestfulBase::controllersInfo().\n   */\n  public function controllersInfo() {\n    return array(\n      '.*' => array(\n        // Get or create a new token.\n        RequestInterface::METHOD_GET => 'refreshToken',\n      ),\n    );\n  }\n\n  /**\n   * Create a token for a user, and return its value.\n   *\n   * @param string $token\n   *   The refresh token.\n   *\n   * @throws BadRequestException\n   *\n   * @return RestfulTokenAuth\n   *   The new access token.\n   */\n  public function refreshToken($token) {\n    // Check if there is a token that did not expire yet.\n    /* @var \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntityInterface $data_provider */\n    $data_provider = $this->getDataProvider();\n    $query = $data_provider->EFQObject();\n    $results = $query\n      ->entityCondition('entity_type', $this->entityType)\n      ->entityCondition('bundle', 'refresh_token')\n      ->propertyCondition('token', $token)\n      ->range(0, 1)\n      ->execute();\n\n    if (empty($results['restful_token_auth'])) {\n      throw new BadRequestException('Invalid refresh token.');\n    }\n\n    // Remove the refresh token once used.\n    $refresh_token = entity_load_single('restful_token_auth', key($results['restful_token_auth']));\n    $uid = $refresh_token->uid;\n\n    // Get the access token linked to this refresh token then do some cleanup.\n    $access_token_query = new EntityFieldQuery();\n    $access_token_reference = $access_token_query\n      ->entityCondition('entity_type', 'restful_token_auth')\n      ->entityCondition('bundle', 'access_token')\n      ->fieldCondition('refresh_token_reference', 'target_id', $refresh_token->id)\n      ->range(0, 1)\n      ->execute();\n\n    if (!empty($access_token_reference['restful_token_auth'])) {\n      $access_token = key($access_token_reference['restful_token_auth']);\n      entity_delete('restful_token_auth', $access_token);\n    }\n\n    $refresh_token->delete();\n\n    // Create the new access token and return it.\n    /* @var \\Drupal\\restful_token_auth\\Entity\\RestfulTokenAuthController $controller */\n    $controller = entity_get_controller($this->getEntityType());\n    $token = $controller->generateAccessToken($uid);\n    return $this->view($token->id);\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_token_auth/src/Plugin/resource/TokenAuthenticationBase.php",
    "content": "<?php\n/**\n * @file\n * Contains Drupal\\restful_token_auth\\Plugin\\resource\\TokenAuthenticationBase.\n */\n\nnamespace Drupal\\restful_token_auth\\Plugin\\resource;\n\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\nabstract class TokenAuthenticationBase extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   *\n   * @see http://tools.ietf.org/html/rfc6750#section-4\n   */\n  public function publicFields() {\n    $public_fields = parent::publicFields();\n    unset($public_fields['label']);\n    unset($public_fields['self']);\n    $public_fields['id']['methods'] = array();\n    $public_fields['access_token'] = array(\n      'property' => 'token',\n    );\n    $public_fields['type'] = array(\n      'callback' => array('\\Drupal\\restful\\RestfulManager::echoMessage', array('Bearer')),\n    );\n    $public_fields['expires_in'] = array(\n      'property' => 'expire',\n      'process_callbacks' => array(\n        '\\Drupal\\restful_token_auth\\Plugin\\resource\\TokenAuthenticationBase::intervalInSeconds',\n      ),\n    );\n    $public_fields['refresh_token'] = array(\n      'property' => 'refresh_token_reference',\n      'process_callbacks' => array(\n        '\\Drupal\\restful_token_auth\\Plugin\\resource\\TokenAuthenticationBase::getTokenFromEntity',\n      ),\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * Process callback helper to get the time difference in seconds.\n   *\n   * @param int $value\n   *   The expiration timestamp in the access token.\n   *\n   * @return int\n   *   Number of seconds before expiration.\n   */\n  public static function intervalInSeconds($value) {\n    $interval = $value - time();\n    return $interval < 0 ? 0 : $interval;\n  }\n\n  /**\n   * Get the token string from the token entity.\n   *\n   * @param int $token_id\n   *   The restful_token_auth entity.\n   *\n   * @return string\n   *   The token string.\n   */\n  public static function getTokenFromEntity($token_id) {\n    if ($token = entity_load_single('restful_token_auth', $token_id)) {\n      return $token->token;\n    }\n    return NULL;\n  }\n\n}\n"
  },
  {
    "path": "modules/restful_token_auth/tests/RestfulTokenAuthenticationTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulTokenAuthenticationTestCase.\n */\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\UnauthorizedException;\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulTokenAuthenticationTestCase extends DrupalWebTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Token Authentication',\n      'description' => 'Test the request authentication with a token.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_token_auth', 'restful_token_auth_test');\n\n    $this->user = $this->drupalCreateUser();\n  }\n\n  /**\n   * Testing the user's access token will be invalidate one the user is blocked.\n   */\n  function testTokenInvalidating() {\n    $this->drupalLogin($this->user);\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPlugin('access_token:1.0');\n\n    // Generating token.\n    $handler->doGet();\n\n    // Blocking the user.\n    user_save($this->user, array('status' => FALSE));\n\n    // Verify the token removed.\n    $query = new EntityFieldQuery();\n    $result = $query\n      ->entityCondition('entity_type', 'restful_token_auth')\n      ->propertyCondition('uid', $this->user->uid)\n      ->execute();\n\n    $this->assertTrue(empty($result), 'The access tokens invalidated when blocking the user.');\n  }\n\n  /**\n   * Test authenticating a user.\n   */\n  function testAuthentication() {\n    // Create user.\n    $this->drupalLogin($this->user);\n\n    // Create \"Article\" node.\n    $title1 = $this->randomName();\n    $settings = array(\n      'type' => 'article',\n      'title' => $title1,\n      'uid' => $this->user->uid,\n    );\n    $node1 = $this->drupalCreateNode($settings);\n    $id = $node1->nid;\n\n    $resource_manager = restful()->getResourceManager();\n    $formatter = restful()->getFormatterManager()->getPlugin('single_json');\n    // Get a token for the user, using the handler.\n    $handler = $resource_manager->getPlugin('access_token:1.0');\n    $formatter->setResource($handler);\n    $result = $formatter->prepare($handler->doGet());\n    $access_token = $result['access_token'];\n    $refresh_token = $result['refresh_token'];\n    $this->assertNotNull($access_token);\n    $this->assertNotNull($refresh_token);\n\n    // Assert the token did not change.\n    $result = $formatter->prepare($handler->doGet());\n    $this->assertEqual($access_token, $result['access_token'], 'Access token did not change.');\n\n    // Get a \"protected\" resource without the access token.\n    $handler = $resource_manager->getPlugin('articles:1.3');\n    $handler->setRequest(Request::create('api/v1.3/articles'));\n    $handler->setPath('');\n    $formatter->setResource($handler);\n    try {\n      // Reset the account to trigger the auth process.\n      $handler->setAccount(NULL);\n      $handler->getAccount();\n      $this->fail('\"Unauthorized\" exception not thrown.');\n    }\n    catch (UnauthorizedException $e) {\n      $this->pass('\"Unauthorized\" exception was thrown.');\n    }\n\n    // Get a \"protected\" resource with invalid access token.\n    $handler->setRequest(Request::create('api/v1.3/articles', array(\n      'access_token' => 'invalid',\n    )));\n    try {\n      // Reset the account to trigger the auth process.\n      $handler->setAccount(NULL);\n      $handler->getAccount();\n      $this->fail('\"Unauthorized\" exception not thrown.');\n    }\n    catch (UnauthorizedException $e) {\n      $this->pass('\"Unauthorized\" exception was thrown.');\n    }\n\n    // Get a \"protected\" resource with refresh token as access token.\n    $handler->setRequest(Request::create('api/v1.3/articles/' . $id, array(\n      'access_token' => 'invalid',\n    )));\n    $handler->setPath($id);\n    try {\n      // Reset the account to trigger the auth process.\n      $handler->setAccount(NULL);\n      $handler->getAccount();\n      $this->fail('\"Unauthorized\" exception not thrown.');\n    }\n    catch (UnauthorizedException $e) {\n      $this->pass('\"Unauthorized\" exception was thrown.');\n    }\n\n    // Get a \"protected\" resource with refresh token.\n    $handler->setRequest(Request::create('api/v1.3/articles/' . $id, array(\n      'refresh_token' => $refresh_token,\n    )));\n    $handler->setPath($id);\n    try {\n      // Reset the account to trigger the auth process.\n      $handler->setAccount(NULL);\n      $handler->getAccount();\n      $this->fail('\"Unauthorized\" exception not thrown.');\n    }\n    catch (UnauthorizedException $e) {\n      $this->pass('\"Unauthorized\" exception was thrown.');\n    }\n\n    // Get a \"protected\" resource with the access token.\n    $response = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL)\n      ->prepare($handler->doGet($id, array('access_token' => $access_token)));\n    $handler->setAccount(NULL);\n    $handler->getAccount();\n    // Validate the returned content.\n    $result = $response['data'][0];\n    $this->assertEqual($result['label'], $title1, 'Article resource can be accessed with valid access token.');\n\n    // Set the expiration token to the past.\n    $query = new \\EntityFieldQuery();\n    $result = $query\n      ->entityCondition('entity_type', 'restful_token_auth')\n      ->entityCondition('bundle', 'access_token')\n      ->propertyCondition('token', $access_token)\n      ->execute();\n\n    if (empty($result['restful_token_auth'])) {\n      $this->fail('No token was found.');\n    }\n\n    // Load the token.\n    $access_id = key($result['restful_token_auth']);\n    $token = entity_load_single('restful_token_auth', $access_id);\n    $token->expire = REQUEST_TIME - 60 * 24;\n    $token->save();\n\n    // Make a GET request to trigger a deletion of the token.\n    $handler = $resource_manager->getPlugin('articles:1.3');\n    $formatter->setResource($handler);\n\n    $handler->setRequest(Request::create('api/v1.3/articles/' . $id, array(\n      'access_token' => $access_token,\n    )));\n    $handler->setPath($id);\n    try {\n      // Reset the account to trigger the auth process.\n      $handler->setAccount(NULL);\n      $handler->getAccount();\n      $this->fail('\"Unauthorized\" exception not thrown for expired token.');\n    }\n    catch (UnauthorizedException $e) {\n      $this->pass('\"Unauthorized\" exception was thrown for expired token.');\n    }\n\n    // Make sure the token was deleted.\n    $query = new \\EntityFieldQuery();\n    $count = $query\n      ->entityCondition('entity_type', 'restful_token_auth')\n      ->entityCondition('bundle', 'access_token')\n      ->propertyCondition('token', $access_token)\n      ->count()\n      ->execute();\n\n    $this->assertFalse($count, 'The token was deleted.');\n\n    // Test the refresh capabilities.\n    $handler = $resource_manager->getPlugin('refresh_token:1.0');\n    $formatter->setResource($handler);\n    $result = $formatter->prepare($handler->doGet($refresh_token));\n    $this->assertNotNull($result['access_token'], 'A new access token granted for a valid refresh token.');\n    $this->assertNotNull($result['refresh_token'], 'A new refresh token granted for a valid refresh token.');\n    $this->assertNotEqual($refresh_token, $result['refresh_token']);\n\n    // Test invalid refresh token.\n    try {\n      $handler->doGet('invalid');\n      $this->fail('\"Bad Request\" exception not thrown.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('\"Bad Request\" exception was thrown.');\n    }\n  }\n\n}\n"
  },
  {
    "path": "restful.admin.inc",
    "content": "<?php\n\nuse Drupal\\restful\\Plugin\\FormatterPluginManager;\n\n/**\n * Menu callback; Admin settings form.\n */\nfunction restful_admin_settings($form_state) {\n  $form = array();\n\n  $form['restful_default_output_formatter'] = array(\n    '#type' => 'radios',\n    '#title' => t('Default formatter'),\n    '#description' => t('Determine the default formatter that would be used.'),\n    '#options' => array(),\n    '#default_value' => variable_get('restful_default_output_formatter', 'json'),\n    '#required' => TRUE,\n  );\n\n  $element = &$form['restful_default_output_formatter'];\n  $formatter_manager = FormatterPluginManager::create();\n\n  foreach ($formatter_manager->getDefinitions() as $plugin_name => $plugin) {\n    $element['#options'][$plugin_name] = check_plain($plugin['label']);\n\n    // Add description for each formatter.\n    if (!$plugin['description']) {\n      continue;\n    }\n\n    $element[$plugin_name]['#description'] = check_plain($plugin['description']);\n  }\n\n  $params = array(\n    '@api' => variable_get('restful_hook_menu_base_path', 'api'),\n  );\n\n  $form['file_upload'] = array(\n    '#type' => 'fieldset',\n    '#title' => t('File upload'),\n  );\n\n  $form['file_upload']['restful_file_upload'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('File upload'),\n    '#description' => t('When enabled a file upload resource will be available.'),\n    '#default_value' => variable_get('restful_file_upload', FALSE),\n  );\n\n  $form['file_upload']['restful_file_upload_allow_anonymous_user'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Anonymous file upload'),\n    '#description' => t('When enabled a file upload resource will be available also for anonymous users.'),\n    '#default_value' => variable_get('restful_file_upload_allow_anonymous_user', FALSE),\n    '#states' => array(\n      'visible' => array(\n        ':input[name=restful_file_upload]' => array('checked' => TRUE),\n      ),\n    ),\n  );\n\n  $form['restful_show_access_denied'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Show access denied records'),\n    '#description' => t('Check this box to get an HTTP 403 error when requesting entities with access denied. Listing denied entities will remove them from the output and have a flag indicating the access violation. Leave it unchecked to hide access denied records. If you do not care about unpriviledged users knowing that records they do not have access to exist, you can check this box.'),\n    '#default_value' => variable_get('restful_show_access_denied', FALSE),\n  );\n\n  $form['restful_allowed_origin'] = array(\n    '#type' => 'textfield',\n    '#title' => t('Allowed origin'),\n    '#description' => t('When you make an XHR (AJAX) call to a resource under a different host, most modern browsers will make an initial OPTIONS request to the resource. The response to that can contain the Access-Control-Allow-Origin, if that includes the domain making the request the browser will allow the cross-domain request. The contents of this field will be used in that header. Use <em>*</em> to allow any origin.'),\n    '#default_value' => variable_get('restful_allowed_origin', ''),\n  );\n\n  $form['advanced'] = array(\n    '#type' => 'fieldset',\n    '#title' => t('Advanced'),\n    '#collapsible' => TRUE,\n    '#collapsed' => TRUE,\n  );\n\n  $form['advanced']['restful_hijack_api_pages'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Hijack API pages'),\n    '#description' => t('When enabled all URLS under @api will be handled by RESTful module.', $params),\n    '#default_value' => variable_get('restful_hijack_api_pages', TRUE),\n  );\n\n  $form['advanced']['restful_hook_menu_base_path'] = array(\n    '#type' => 'textfield',\n    '#title' => t('API Base path'),\n    '#description' => t('Determines the base path of all resources.'),\n    '#default_value' => variable_get('restful_hook_menu_base_path', 'api'),\n  );\n\n  $form['advanced']['restful_enable_user_login_resource'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Login resource'),\n    '#description' => t('Determines if the default user login resource should be enabled.'),\n    '#default_value' => variable_get('restful_enable_user_login_resource', TRUE),\n  );\n\n  $form['advanced']['restful_enable_users_resource'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('User resource'),\n    '#description' => t('Determines if the default user resource should be enabled.'),\n    '#default_value' => variable_get('restful_enable_users_resource', TRUE),\n  );\n\n  $form['advanced']['restful_enable_discovery_resource'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Discovery resource'),\n    '#description' => t('Enable discovery resource which shows all accessible resources under @api URL.', $params),\n    '#default_value' => variable_get('restful_enable_discovery_resource', TRUE),\n  );\n\n  $form['advanced']['restful_global_rate_limit'] = array(\n    '#type' => 'textfield',\n    '#title' => t('Rate limit - hits'),\n    '#description' => t('The number of allowed hits. This is global for all roles. 0 means no global rate limit should be applied.'),\n    '#default_value' => variable_get('restful_global_rate_limit', 0),\n    '#element_validate' => array('element_validate_integer'),\n  );\n\n  $form['advanced']['restful_global_rate_period'] = array(\n    '#type' => 'textfield',\n    '#title' => t('Rate limit - period'),\n    '#description' => t('The period string compatible with <a href=\"@url\">\\DateInterval</a>. After this period the module will restart counting hits.', array('@url' => 'http://php.net/manual/en/dateinterval.createfromdatestring.php')),\n    '#default_value' => variable_get('restful_global_rate_period', 'P1D'),\n    '#element_validate' => array('restful_date_time_format_element_validate'),\n  );\n\n  return system_settings_form($form);\n}\n"
  },
  {
    "path": "restful.api.php",
    "content": "<?php\n\n/**\n * @file\n * Hooks provided by the RESTful module.\n */\n\n/**\n * @addtogroup hooks\n * @{\n */\n\n\n/**\n * Allow altering the request before it is processed.\n *\n * @param \\Drupal\\restful\\Http\\RequestInterface $request\n *   The request object.\n */\nfunction hook_restful_parse_request_alter(\\Drupal\\restful\\Http\\RequestInterface &$request) {\n  // Allow implementor modules to alter the request object.\n  $request->setApplicationData('csrf_token', 'token');\n}\n\n/**\n * Allow altering the request before it is processed.\n *\n * @param \\Drupal\\restful\\Plugin\\resource\\ResourceInterface &$resource\n *   The resource object to alter.\n */\nfunction hook_restful_resource_alter(\\Drupal\\restful\\Plugin\\resource\\ResourceInterface &$resource) {\n  // Chain a decorator with the passed in resource based on the resource\n  // annotation definition.\n  $plugin_definition = $resource->getPluginDefinition();\n  if (!empty($plugin_definition['renderCache']) && !empty($plugin_definition['renderCache']['render'])) {\n    $resource = new \\Drupal\\restful\\Plugin\\resource\\CachedResource($resource);\n  }\n}\n\n/**\n * @} End of \"addtogroup hooks\".\n */\n"
  },
  {
    "path": "restful.cache.inc",
    "content": "<?php\n\n/**\n * @file\n * Procedural implementations for cache related features.\n */\nuse Drupal\\restful\\RenderCache\\RenderCache;\n\n/**\n * Clears all caches and associated fragments.\n */\nfunction restful_clear_caches() {\n  /* @var \\Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController $controller */\n  $controller = entity_get_controller('cache_fragment');\n  $controller->wipe();\n  cache_clear_all('*', RenderCache::CACHE_BIN, TRUE);\n  drupal_set_message(t('RESTful caches were successfully cleared.'));\n}\n\n/**\n * Implements hook_flush_caches().\n */\nfunction restful_flush_caches() {\n  if (!variable_get('restful_clear_on_cc_all', FALSE)) {\n    return array();\n  }\n  // Delete all the cache fragments.\n  /* @var \\Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController $controller */\n  $controller = entity_get_controller('cache_fragment');\n  $controller->wipe();\n  return array(RenderCache::CACHE_BIN);\n}\n\n/**\n * Menu callback; Admin settings form.\n */\nfunction restful_admin_cache_settings($form_state) {\n  $form = array();\n  $form['restful_page_cache'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Page cache'),\n    '#description' => t('RESTful can leverage page cache, this will boost your performace for anonymous traffic. !link to start caching responses. Status: <strong>@status</strong>. <strong>CAUTION:</strong> If your resources are using authentication providers other than cookie, you will want to turn this off. Otherwise you may get cached anonymous values for your authenticated GET requests.', array(\n      '!link' => l(t('Enable page cache'), 'admin/config/development/performance'),\n      '@status' => variable_get('cache', FALSE) ? t('Enabled') : t('Disabled'),\n    )),\n    '#disabled' => !variable_get('cache', FALSE),\n    '#default_value' => variable_get('restful_page_cache', FALSE) && variable_get('cache', FALSE),\n  );\n\n  $form['restful_render_cache'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Cache results'),\n    '#description' => t('When enabled any resource that has not explicitly disabled the caching will be cached. Note that the first hit may result with slower response, although the next ones would be significantly faster. This is different from the page cache in the sense that it acts at the row level (a single entity, a single database row, ...), therefore allowing you to assemble non cached pages with the cached bits faster.'),\n    '#default_value' => variable_get('restful_render_cache', FALSE),\n  );\n\n  $form['clear_restful'] = array(\n    '#submit' => array('restful_clear_caches'),\n    '#type' => 'submit',\n    '#value' => t('Clear render caches'),\n    '#disabled' => !variable_get('restful_render_cache', FALSE) && user_access('restful clear render caches'),\n  );\n\n  $form['restful_clear_on_cc_all'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Clear on global flush'),\n    '#description' => t(\"Check this box to clear the render caches when clearing Drupal's caches. In general the render caches are more robust than the TTL based caches. The recommended value is unchecked.\"),\n    '#default_value' => variable_get('restful_clear_on_cc_all', FALSE),\n  );\n\n  $form['restful_fast_cache_clear'] = array(\n    '#type' => 'checkbox',\n    '#title' => t('Fast cache clear'),\n    '#description' => t('A lot of cache fragment entries may be created by default. This may cause your cache clears to be slow. By checking this checkbox the cache fragments are deleted from the database in a fast manner. As a trade-in, no hook_entity_delete will be fired for the cache fragment entities. This is OK in the vast majority of the cases. You can mitigate the number of generated fragments by overriding the \"getCacheContext\" method in your data provider.'),\n    '#default_value' => variable_get('restful_fast_cache_clear', TRUE),\n  );\n\n  return system_settings_form($form);\n}\n"
  },
  {
    "path": "restful.entity.inc",
    "content": "<?php\n\n/**\n * @file\n * Contains entity related code.\n */\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResourceInterface;\nuse Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController;\nuse Drupal\\restful\\RenderCache\\RenderCache;\n\n/**\n * Implements hook_entity_info().\n */\nfunction restful_entity_info() {\n  $items['rate_limit'] = array(\n    'label' => t('Rate limit'),\n    'entity class' => '\\\\Drupal\\\\restful\\\\RateLimit\\\\Entity\\\\RateLimit',\n    'controller class' => '\\\\Drupal\\\\restful\\\\RateLimit\\\\Entity\\\\RateLimitController',\n    'base table' => 'restful_rate_limit',\n    'fieldable' => TRUE,\n    'entity keys' => array(\n      'id' => 'rlid',\n      'label' => 'identifier',\n      'bundle' => 'event',\n    ),\n    'bundles' => array(),\n    'bundle keys' => array(\n      'bundle' => 'type',\n    ),\n    'module' => 'restful',\n    'entity cache' => module_exists('entitycache'),\n  );\n  $items['cache_fragment'] = array(\n    'label' => t('Cache fragment'),\n    'entity class' => '\\\\Drupal\\\\restful\\\\RenderCache\\\\Entity\\\\CacheFragment',\n    'controller class' => '\\\\Drupal\\\\restful\\\\RenderCache\\\\Entity\\\\CacheFragmentController',\n    'base table' => 'restful_cache_fragment',\n    'fieldable' => FALSE,\n    'entity keys' => array(\n      'id' => 'tid',\n      'label' => 'identifier',\n      'bundle' => 'type',\n    ),\n    'bundles' => array(),\n    'bundle keys' => array(\n      'bundle' => 'type',\n    ),\n    'module' => 'restful',\n    'entity cache' => FALSE,\n  );\n\n  return $items;\n}\n\n/**\n * Helper function that extract cache hashes from an entity.\n */\nfunction _restful_entity_cache_hashes($entity, $type) {\n  if ($type == 'cache_fragment') {\n    return array();\n  }\n  // Limit to the fragments for our entity type.\n  list($entity_id) = entity_extract_ids($type, $entity);\n  $query = new \\EntityFieldQuery();\n  $query\n    ->entityCondition('entity_type', 'cache_fragment')\n    ->propertyCondition('type', 'entity')\n    ->propertyCondition('value', CacheDecoratedResource::serializeKeyValue($type, $entity_id));\n  return CacheFragmentController::lookUpHashes($query);\n}\n\n/**\n * Implements hook_entity_update().\n */\nfunction restful_entity_update($entity, $type) {\n  $hashes = &drupal_static('restful_entity_clear_hashes', array());\n  $new_hashes = _restful_entity_cache_hashes($entity, $type);\n  array_walk($new_hashes, '_restful_entity_clear_all_resources');\n  $hashes += $new_hashes;\n  restful_register_shutdown_function_once('restful_entity_clear_render_cache');\n}\n\n/**\n * Implements hook_entity_delete().\n */\nfunction restful_entity_delete($entity, $type) {\n  $hashes = &drupal_static('restful_entity_clear_hashes', array());\n  $new_hashes = _restful_entity_cache_hashes($entity, $type);\n  array_walk($new_hashes, '_restful_entity_clear_all_resources');\n  $hashes += $new_hashes;\n  restful_register_shutdown_function_once('restful_entity_clear_render_cache');\n}\n\n/**\n * Implements hook_user_update().\n */\nfunction restful_user_update(&$edit, $account, $category) {\n  // Search for all the cache fragments with our entity id.\n  $query = new \\EntityFieldQuery();\n  $query\n    ->entityCondition('entity_type', 'cache_fragment')\n    ->propertyCondition('type', 'user_id')\n    ->propertyCondition('value', $account->uid);\n  $hashes = &drupal_static('restful_entity_clear_hashes', array());\n  $new_hashes = CacheFragmentController::lookUpHashes($query);\n  array_walk($new_hashes, '_restful_entity_clear_all_resources');\n  $hashes += $new_hashes;\n  restful_register_shutdown_function_once('restful_entity_clear_render_cache');\n}\n\n/**\n * Implements hook_user_delete().\n */\nfunction restful_user_delete($account) {\n  // Search for all the cache fragments with our entity id.\n  $query = new \\EntityFieldQuery();\n  $query\n    ->entityCondition('entity_type', 'cache_fragment')\n    ->propertyCondition('type', 'user_id')\n    ->propertyCondition('value', $account->uid);\n  $hashes = &drupal_static('restful_entity_clear_hashes', array());\n  $new_hashes = CacheFragmentController::lookUpHashes($query);\n  array_walk($new_hashes, '_restful_entity_clear_all_resources');\n  $hashes += $new_hashes;\n  restful_register_shutdown_function_once('restful_entity_clear_render_cache');\n}\n\n/**\n * Helper function to schedule a shutdown once.\n *\n * @param callable $callback\n *   The callback.\n */\nfunction restful_register_shutdown_function_once($callback) {\n  $existing_callbacks = drupal_register_shutdown_function();\n  $added = (bool) array_filter($existing_callbacks, function ($item) use ($callback) {\n    return $item['callback'] == $callback;\n  });\n  if (!$added) {\n    drupal_register_shutdown_function($callback);\n  }\n}\n\n/**\n * Clear the cache back ends for the given hash.\n *\n * @param string $cid\n *   The cache ID to clear.\n */\nfunction _restful_entity_clear_all_resources($cid) {\n  if (!$instance_id = CacheFragmentController::resourceIdFromHash($cid)) {\n    return;\n  }\n  try {\n    $handler = restful()->getResourceManager()->getPlugin($instance_id);\n  }\n  catch (ServerConfigurationException $e) {\n    watchdog_exception('restful', $e);\n    return;\n  }\n  if (!$handler instanceof CacheDecoratedResourceInterface) {\n    return;\n  }\n  // Clear the cache bin.\n  $handler->getCacheController()->clear($cid);\n}\n\n/**\n * Delete the scheduled fragments and caches on shutdown.\n */\nfunction restful_entity_clear_render_cache() {\n  if ($hashes = drupal_static('restful_entity_clear_hashes', array())) {\n    $hashes = array_unique($hashes);\n    drupal_static_reset('restful_entity_clear_hashes');\n    $resource_manager = restful()->getResourceManager();\n    foreach ($hashes as $hash) {\n      if (!$instance_id = CacheFragmentController::resourceIdFromHash($hash)) {\n        continue;\n      }\n      $handler = $resource_manager->getPlugin($instance_id);\n      if (!$handler instanceof CacheDecoratedResourceInterface) {\n        continue;\n      }\n      if (!$handler->hasSimpleInvalidation()) {\n        continue;\n      }\n      // You can get away without the fragments for a clear.\n      $cache_object = new RenderCache(new ArrayCollection(), $hash, $handler->getCacheController());\n      // Do a clear with the RenderCache object to also remove the cache\n      // fragment entities.\n      $cache_object->clear();\n    }\n  }\n}\n"
  },
  {
    "path": "restful.info",
    "content": "name = RESTful\ndescription = Turn Drupal to a RESTful server, following best practices.\ncore = 7.x\nphp = 5.5.9\ndependencies[] = entity\ndependencies[] = plug\nconfigure = admin/config/services/restful\n\nregistry_autoload[] = PSR-0\nregistry_autoload[] = PSR-4\n\n; Temporary workaround to allow RESTful to work fine on PHP7.\nregistry_autoload_files[] = src/Util/ExplorableDecoratorInterface.php\n\n; Tests\nfiles[] = tests/RestfulAuthenticationTestCase.test\nfiles[] = tests/RestfulCommentTestCase.test\nfiles[] = tests/RestfulCreateEntityTestCase.test\nfiles[] = tests/RestfulCreateNodeTestCase.test\nfiles[] = tests/RestfulCreatePrivateNodeTestCase.test\nfiles[] = tests/RestfulCreateTaxonomyTermTestCase.test\nfiles[] = tests/RestfulCsrfTokenTestCase.test\nfiles[] = tests/RestfulCurlBaseTestCase.test\nfiles[] = tests/RestfulDataProviderPlugPluginsTestCase.test\nfiles[] = tests/RestfulDbQueryTestCase.test\nfiles[] = tests/RestfulVariableTestCase.test\nfiles[] = tests/RestfulDiscoveryTestCase.test\nfiles[] = tests/RestfulEntityAndPropertyAccessTestCase.test\nfiles[] = tests/RestfulEntityUserAccessTestCase.test\nfiles[] = tests/RestfulEntityValidatorTestCase.test\nfiles[] = tests/RestfulExceptionHandleTestCase.test\nfiles[] = tests/RestfulForbiddenItemsTestCase.test\nfiles[] = tests/RestfulGetHandlersTestCase.test\nfiles[] = tests/RestfulHalJsonTestCase.test\nfiles[] = tests/RestfulHookMenuTestCase.test\nfiles[] = tests/RestfulJsonApiTestCase.test\nfiles[] = tests/RestfulListEntityMultipleBundlesTestCase.test\nfiles[] = tests/RestfulListTestCase.test\nfiles[] = tests/RestfulRateLimitTestCase.test\nfiles[] = tests/RestfulReferenceTestCase.test\nfiles[] = tests/RestfulRenderCacheTestCase.test\nfiles[] = tests/RestfulSimpleJsonTestCase.test\nfiles[] = tests/RestfulUpdateEntityTestCase.test\nfiles[] = tests/RestfulSubResourcesCreateEntityTestCase.test\nfiles[] = tests/RestfulUpdateEntityCurlTestCase.test\nfiles[] = tests/RestfulUserLoginCookieTestCase.test\nfiles[] = tests/RestfulViewEntityMultiLingualTestCase.test\nfiles[] = tests/RestfulViewEntityTestCase.test\nfiles[] = tests/RestfulViewModeAndFormatterTestCase.test\n"
  },
  {
    "path": "restful.install",
    "content": "<?php\n\n/**\n * @file\n * Install, update, and uninstall functions for the RESTful module.\n */\n\n/**\n * Implements hook_schema().\n */\nfunction restful_schema() {\n  $schema = array();\n\n  $schema['cache_restful'] = drupal_get_schema_unprocessed('system', 'cache');\n\n  // Rate limit entity base table.\n  $schema['restful_rate_limit'] = array(\n    'description' => 'Rate limit base table',\n    'fields' => array(\n      'rlid' => array(\n        'description' => 'The rate limit unique ID.',\n        'type' => 'serial',\n        'unsigned' => TRUE,\n        'not null' => TRUE,\n      ),\n      'event' => array(\n        'description' => 'The event name.',\n        'type' => 'varchar',\n        'length' => 64,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'identifier' => array(\n        'description' => 'The user & request identifier.',\n        'type' => 'varchar',\n        'length' => 128,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'timestamp' => array(\n        'description' => 'The Unix timestamp when the rate limit window started.',\n        'type' => 'int',\n        'not null' => FALSE,\n        'default' => NULL,\n      ),\n      'expiration' => array(\n        'description' => 'The Unix timestamp when the rate limit window expires.',\n        'type' => 'int',\n        'not null' => FALSE,\n        'default' => NULL,\n      ),\n      'hits' => array(\n        'description' => 'The number of hits.',\n        'type' => 'int',\n        'not null' => FALSE,\n        'default' => 0,\n      ),\n    ),\n    'unique keys' => array(\n      'identifier' => array('identifier'),\n    ),\n    'indexes' => array(\n      'rate_limit_identifier' => array('identifier'),\n    ),\n    'primary key' => array('rlid'),\n  );\n\n  // Cache fragment entity base table.\n  $schema['restful_cache_fragment'] = array(\n    'description' => 'Cache fragment base table',\n    'fields' => array(\n      'tid' => array(\n        'description' => 'The cache fragment unique ID.',\n        'type' => 'serial',\n        'unsigned' => TRUE,\n        'not null' => TRUE,\n      ),\n      'type' => array(\n        'description' => 'The type of the cache fragment, e.g \"entity_id\".',\n        'type' => 'varchar',\n        'length' => 64,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'value' => array(\n        'description' => 'The value for the tag. Example: 182.',\n        'type' => 'varchar',\n        'length' => 255,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'hash' => array(\n        'description' => 'The hash used as a cache ID.',\n        'type' => 'char',\n        'length' => 40,\n        'not null' => FALSE,\n        'default' => NULL,\n      ),\n    ),\n    'indexes' => array(\n      'cache_fragment_hash' => array('hash'),\n    ),\n    'unique keys' => array(\n      'hash_key_val' => array('type', 'value', 'hash'),\n    ),\n    'primary key' => array('tid'),\n  );\n  return $schema;\n}\n\n/**\n * Implements hook_uninstall().\n */\nfunction restful_uninstall() {\n  variable_del('restful_default_output_formatter');\n\n  variable_del('restful_enable_discovery_resource');\n\n  variable_del('restful_file_upload');\n  variable_del('restful_file_upload_allow_anonymous_user');\n\n  variable_del('restful_hijack_api_pages');\n  variable_del('restful_hook_menu_base_path');\n\n  variable_del('restful_enable_user_login_resource');\n\n  variable_del('restful_global_rate_limit');\n  variable_del('restful_global_rate_period');\n\n  variable_del('restful_enable_users_resource');\n\n  variable_del('restful_render_cache');\n  variable_del('restful_skip_basic_auth');\n\n  variable_del('restful_allowed_origin');\n}\n\n/**\n * Create the cache fragments schema.\n */\nfunction restful_update_7200() {\n  $table_schema = drupal_get_schema('restful_cache_fragment', TRUE);\n  db_create_table('restful_cache_fragment', $table_schema);\n}\n\n/**\n * Clear RESTful cache on cache flush.\n */\nfunction restful_update_7201() {\n  // Even if the recommended value is FALSE, there might be some deploy\n  // workflows that assume cache clearing.\n  variable_set('restful_clear_on_cc_all', TRUE);\n}\n"
  },
  {
    "path": "restful.module",
    "content": "<?php\n\n/**\n * @file\n * Turn Drupal to a RESTful server, following best practices.\n */\n\ninclude_once __DIR__ . '/restful.entity.inc';\ninclude_once __DIR__ . '/restful.cache.inc';\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\RestfulException;\nuse Drupal\\restful\\Http\\HttpHeader;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Http\\Response;\nuse Drupal\\restful\\Http\\ResponseInterface;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\RateLimitDecoratedResource;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\RestfulManager;\n\n/**\n * Implements hook_menu().\n */\nfunction restful_menu() {\n  $base_path = variable_get('restful_hook_menu_base_path', 'api');\n  $items = array();\n  $plugins = restful()\n    ->getResourceManager()\n    ->getPlugins();\n  foreach ($plugins->getIterator() as $plugin) {\n    if (!$plugin instanceof ResourceInterface) {\n      // If the plugin is disabled $plugin gets set to NULL. If that is the case\n      // do not set any menu values based on it.\n      continue;\n    }\n    $plugin_definition = $plugin->getPluginDefinition();\n    if (!$plugin_definition['hookMenu']) {\n      // Plugin explicitly declared no hook menu should be created automatically\n      // for it.\n      continue;\n    }\n    $item = array(\n      'title' => $plugin_definition['name'],\n      'access callback' => RestfulManager::FRONT_CONTROLLER_ACCESS_CALLBACK,\n      'access arguments' => array($plugin_definition['resource']),\n      'page callback' => RestfulManager::FRONT_CONTROLLER_CALLBACK,\n      'page arguments' => array($plugin_definition['resource']),\n      'delivery callback' => 'restful_delivery',\n      'type' => MENU_CALLBACK,\n    );\n    // If there is no specific menu item allow the different version variations.\n    if (!isset($plugin_definition['menuItem'])) {\n      // Add the version string to the arguments.\n      $item['access arguments'][] = 1;\n      $item['page arguments'][] = 1;\n      // Ex: api/v1.2/articles\n      $items[$base_path . '/v' . $plugin_definition['majorVersion'] . '.' . $plugin_definition['minorVersion'] . '/' . $plugin_definition['resource']] = $item;\n      // Ex: api/v1/articles will use the latest minor version.\n      $items[$base_path . '/v' . $plugin_definition['majorVersion'] . '/' . $plugin_definition['resource']] = $item;\n      // Ex: api/articles will use the header or the latest version.\n      // Do not add the version string to the arguments.\n      $item['access arguments'] = $item['page arguments'] = array(1);\n      $items[$base_path . '/' . $plugin_definition['resource']] = $item;\n    }\n    else {\n      $path = implode('/', array($base_path, $plugin_definition['menuItem']));\n\n      // Remove trailing slashes that can lead to 404 errors.\n      $path = rtrim($path, '/');\n\n      $items[$path] = $item;\n    }\n  }\n\n  // Make sure the Login endpoint has the correct access callback.\n  if (!empty($items[$base_path . '/login'])) {\n    $items[$base_path . '/login']['access callback'] = 'user_is_anonymous';\n  }\n\n  // Add administration page.\n  $items['admin/config/services/restful'] = array(\n    'title' => 'RESTful',\n    'description' => 'Administer the RESTful module.',\n    'page callback' => 'drupal_get_form',\n    'page arguments' => array('restful_admin_settings'),\n    'access arguments' => array('administer restful'),\n    'file' => 'restful.admin.inc',\n  );\n  $items['admin/config/services/restful/restful'] = $items['admin/config/services/restful'];\n  $items['admin/config/services/restful/restful']['type'] = MENU_DEFAULT_LOCAL_TASK;\n  // Add cache administration page.\n  $items['admin/config/services/restful/cache'] = array(\n    'title' => 'Cache',\n    'description' => 'Administer the RESTful module cache system.',\n    'page callback' => 'drupal_get_form',\n    'page arguments' => array('restful_admin_cache_settings'),\n    'access arguments' => array('administer restful'),\n    'file' => 'restful.cache.inc',\n    'type' => MENU_LOCAL_TASK,\n    'weight' => 2,\n  );\n\n  return $items;\n}\n\n/**\n * Implements hook_permission().\n */\nfunction restful_permission() {\n  return array(\n    'administer restful' => array(\n      'title' => t('Administer the RESTful module'),\n      'description' => t('Access the administration pages for the RESTful module.'),\n    ),\n    'administer restful resources' => array(\n      'title' => t('Administer the resources'),\n      'description' => t('Perform operations on the resources.'),\n    ),\n    'restful clear render caches' => array(\n      'title' => t('Clear RESTful render caches'),\n      'description' => t('Clear the render caches and their correspoding cache fragments.'),\n    ),\n  );\n}\n\n/**\n * Implements hook_help().\n */\nfunction restful_help($path, $arg) {\n  switch ($path) {\n    case 'admin/config/services/restful':\n    case 'admin/help#restful':\n      $message = t('This module is managed in GitHub. Please make sure to read the files in the !link folder for more help.', array(\n        '!link' => l(t('Docs'), 'https://github.com/RESTful-Drupal/restful/tree/7.x-2.x/docs'),\n      ));\n      return '<p>' . $message . '</p>';\n\n    case 'admin/config/services/restful/cache':\n      $message = t('The RESTful module contains several layers of caching for enhanced performance: (1) page cache (aka URL level caching) for anonymous users. This cache is extremely fast, but not very flexible. (2) The render cache can be configured for each resource and allows you to serve cached versions of your records (even to authenticated users!). The render cache also contains smart invalidation, which means that you do not need to have a TTL based cache system. Instead the caches are evicted when automatically when necessary.');\n      return '<p>' . $message . '</p>';\n\n  }\n}\n\n/**\n * Get the RestfulManager.\n *\n * Calling restful() from anywhere in the code will give you access to the\n * RestfulManager. That in turn will provide you access to all the elements\n * involved.\n *\n * @return RestfulManager\n *   The manager.\n */\nfunction restful() {\n  static $manager;\n  if (!isset($manager)) {\n    $manager = RestfulManager::createFromGlobals();\n  }\n  return $manager;\n}\n\n/**\n * Access callback; Determine access for an API call.\n *\n * @param string $resource_name\n *   The name of the resource (e.g. \"articles\").\n *\n * @param string $version_string\n *   The version array.\n *\n * @return bool\n *   TRUE if user is allowed to access resource.\n */\nfunction restful_menu_access_callback($resource_name, $version_string = NULL) {\n  $resource_manager = restful()->getResourceManager();\n  if (!empty($version_string) && preg_match('/v[0-9]+(\\.[0-9]+)?/', $version_string)) {\n    $version_string = substr($version_string, 1);\n    $parsed_versions = explode('.', $version_string);\n    if (count($parsed_versions) == 2) {\n      // If there is only the major we need to get the version from the request,\n      // to get the latest version within the major version.\n      $versions = $parsed_versions;\n    }\n  }\n  if (empty($versions) && !$versions = $resource_manager->getVersionFromRequest()) {\n    // No version could be found.\n    return FALSE;\n  }\n\n  try {\n    $instance_id = $resource_name . PluginBase::DERIVATIVE_SEPARATOR . implode('.', $versions);\n    $resource = $resource_manager->getPlugin($instance_id, restful()->getRequest());\n    if (!$resource) {\n      // Throw a PluginNotFoundException exception instead of a denied access.\n      throw new PluginNotFoundException($instance_id);\n    }\n    return $resource->access();\n  }\n  catch (RestfulException $e) {\n    // We can get here if the request method is not valid or if no resource can\n    // be negotiated.\n    $response = restful()->getResponse();\n    $output = _restful_build_http_api_error($e, $response);\n    $response->setStatusCode($e->getCode());\n    $response->setContent(drupal_json_encode($output));\n    $response->send();\n    exit();\n  }\n  catch (PluginNotFoundException $e) {\n    restful_delivery(MENU_NOT_FOUND);\n    exit();\n  }\n}\n\n/**\n * Page callback; Return the response for an API call.\n *\n * @param string $resource_name\n *   The name of the resource (e.g. \"articles\").\n * @param string $version\n *   The version, prefixed with v (e.g. v1, v2.2).\n *\n * @throws \\Drupal\\restful\\Exception\\ServiceUnavailableException\n *\n * @return string\n *   JSON output with the result of the API call.\n *\n * @see http://tools.ietf.org/html/draft-nottingham-http-problem-06\n */\nfunction restful_menu_process_callback($resource_name, $version = NULL) {\n  $path = func_get_args();\n  array_shift($path);\n  if (preg_match('/^v\\d+(\\.\\d+)?$/', $version)) {\n    array_shift($path);\n  }\n  $resource_manager = restful()->getResourceManager();\n  list($major_version, $minor_version) = $resource_manager->getVersionFromRequest();\n  $request = restful()->getRequest();\n  $request->setViaRouter(TRUE);\n  $resource = $resource_manager->getPlugin($resource_name . PluginBase::DERIVATIVE_SEPARATOR . $major_version . '.' . $minor_version, $request);\n\n  $response_headers = restful()\n    ->getResponse()\n    ->getHeaders();\n\n  $version_array = $resource->getVersion();\n  $version_string = 'v' . $version_array['major'] . '.' . $version_array['minor'];\n  $response_headers->add(HttpHeader::create('X-API-Version', $version_string));\n\n  // Vary the response with the presence of the X-API-Version or Accept headers.\n  $vary = $request\n    ->getHeaders()\n    ->get('Vary')\n    ->getValueString() ?: '';\n  $additional_variations = array($vary, 'Accept');\n  if ($x_api_version = $request\n    ->getHeaders()\n    ->get('X-API-Version')\n    ->getValueString()) {\n    $additional_variations[] = 'X-API-Version';\n  }\n  if ($additional_variations) {\n    $response_headers->append(HttpHeader::create('Vary', implode(',', $additional_variations)));\n  }\n\n  // Always add the allow origin if configured.\n  $plugin_definition = $resource->getPluginDefinition();\n  if (!empty($plugin_definition['allowOrigin'])) {\n    $response_headers->append(HttpHeader::create('Access-Control-Allow-Origin', $plugin_definition['allowOrigin']));\n  }\n\n  try {\n    $resource->setPath(implode('/', $path));\n    $result = $resource->process();\n  }\n  catch (RestfulException $e) {\n    $result = _restful_build_http_api_error($e);\n  }\n  catch (Exception $e) {\n    $result = array(\n      'type' => 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1',\n      'title' => $e->getMessage(),\n      'status' => 500,\n    );\n  }\n\n  // If the user was switched during the execution thread, then switch it back.\n  $resource->switchUserBack();\n  return $result;\n}\n\n/**\n * Returns data in JSON format.\n *\n * We do not use drupal_json_output(), in order to maintain the \"Content-Type\"\n * header.\n *\n * @param mixed $var\n *   (optional) If set, the variable will be converted to JSON and output.\n *\n * @see restful_menu_process_callback()\n */\nfunction restful_delivery($var = NULL) {\n  if (!isset($var)) {\n    return;\n  }\n  $response = _restful_delivery_fill_reponse($var, restful()->getResponse());\n  $response->send();\n}\n\n/**\n * Gets the response object to be send.\n *\n * @param mixed $var\n *   If set, the variable will be converted to JSON and output.\n * @param ResponseInterface $response\n *   If set, this response will be used to add the response data.\n *\n * @return ResponseInterface\n *   A prepared response for sending.\n */\nfunction _restful_delivery_fill_reponse($var, ResponseInterface $response = NULL) {\n  $request = restful()->getRequest();\n  $response = $response ? $response : new Response();\n  if (!empty($var['status'])) {\n    $response->setStatusCode($var['status']);\n  }\n  if (is_int($var)) {\n    _restful_get_data_from_menu_status($var);\n    if (!empty($var['status'])) {\n      $response->setStatusCode($var['status']);\n    }\n\n    try {\n      // Adhere to the API Problem draft proposal.\n      $formatter_id = variable_get('restful_default_output_formatter', 'json');\n      // Get the data in the default output format.\n      $data = restful()\n        ->getFormatterManager()\n        ->negotiateFormatter(NULL, $formatter_id)\n        ->format($var);\n\n      $response->setContent($data);\n      $response->prepare($request);\n      return $response;\n    }\n    catch (RestfulException $e) {\n      // If there is an exception during delivery, just JSON encode this.\n      $output = _restful_build_http_api_error($e, $response);\n      $response->setStatusCode($e->getCode());\n      $response->setContent(drupal_json_encode($output));\n      return $response;\n    }\n  }\n\n  try {\n    // Get the formatter for the current resource.\n    $resource = restful()\n      ->getResourceManager()\n      ->negotiate();\n    // Get a new formatter manager.\n    $formatter_manager = restful()\n      ->getFormatterManager();\n    $formatter_manager->setResource($resource);\n    $plugin_definition = $resource->getPluginDefinition();\n    if ($request->getMethod() == RequestInterface::METHOD_OPTIONS) {\n      // There is no guarantee that other formatters can process the\n      // auto-discovery output correctly.\n      $formatter_name = 'json';\n    }\n    else {\n      $formatter_name = isset($plugin_definition['formatter']) ? $plugin_definition['formatter'] : NULL;\n    }\n    $output = $formatter_manager->format($var, $formatter_name);\n    $response->setContent($output);\n  }\n  catch (RestfulException $e) {\n    // Handle if the formatter does not exist.\n    $output = _restful_build_http_api_error($e, $response);\n    $response->setStatusCode($e->getCode());\n    $response->setContent(drupal_json_encode($output));\n    return $response;\n  }\n\n  $response->prepare($request);\n  return $response;\n}\n\n/**\n * Convert a menu status response to a valid JSON.\n *\n * @param int $var\n *   The integer value of the menu status, passed by reference.\n */\nfunction _restful_get_data_from_menu_status(&$var) {\n  switch ($var) {\n    case MENU_NOT_FOUND:\n      $class_name = '\\Drupal\\restful\\Exception\\NotFoundException';\n      $message = 'Invalid URL path.';\n      break;\n\n    case MENU_ACCESS_DENIED:\n      $class_name = '\\Drupal\\restful\\Exception\\ForbiddenException';\n      $message = 'Access denied.';\n      break;\n\n    case MENU_SITE_OFFLINE:\n      $class_name = '\\Drupal\\restful\\Exception\\ServiceUnavailableException';\n      $message = 'Site is offline.';\n      break;\n\n    default:\n      $class_name = '\\Drupal\\restful\\Exception\\RestfulException';\n      $message = 'Unknown exception';\n  }\n\n  $var = _restful_build_http_api_error(new $class_name($message));\n}\n\n/**\n * Helper function to build the structured array for the error output.\n *\n * @param RestfulException $exception\n *   The exception.\n * @param ResponseInterface $response\n *   The response object to alter.\n *\n * @return array\n *   The structured output.\n */\nfunction _restful_build_http_api_error(RestfulException $exception, ResponseInterface $response = NULL) {\n  $response = $response ?: restful()->getResponse();\n  // Adhere to the API Problem draft proposal.\n  $exception->setHeader('Content-Type', 'application/problem+json; charset=utf-8');\n  $result = array(\n    'type' => $exception->getType(),\n    'title' => $exception->getMessage(),\n    'status' => $exception->getCode(),\n    'detail' => $exception->getDescription(),\n  );\n\n  if ($instance = $exception->getInstance()) {\n    $result['instance'] = $instance;\n  }\n\n  if ($errors = $exception->getFieldErrors()) {\n    $result['errors'] = $errors;\n  }\n\n  $headers = $response->getHeaders();\n  foreach ($exception->getHeaders() as $header_name => $header_value) {\n    $headers->add(HttpHeader::create($header_name, $header_value));\n  }\n  drupal_page_is_cacheable(FALSE);\n\n  // Add a log entry with the error / warning.\n  if ($exception->getCode() < 500) {\n    // Even though it's an exception, it's in fact not a server error - it\n    // might be just access denied, or a bad request, so we just want to log\n    // it, but without marking it as an actual exception.\n    watchdog('restful', $exception->getMessage());\n  }\n  else {\n    watchdog_exception('restful', $exception);\n  }\n  return $result;\n}\n\n/**\n * Implements hook_page_delivery_callback_alter().\n *\n * Hijack api/* to be under RESTful. We make sure that any call to api/* pages\n * that isn't valid, will still return with a well formatted error, instead of\n * a 404 HTML page.\n */\nfunction restful_page_delivery_callback_alter(&$callback) {\n  if (!variable_get('restful_hijack_api_pages', TRUE)) {\n    return;\n  }\n\n  $base_path = variable_get('restful_hook_menu_base_path', 'api');\n\n  if (strpos($_GET['q'], $base_path . '/') !== 0 && $_GET['q'] != $base_path) {\n    // Page doesn't start with the base path (e.g. \"api\" or \"api/\").\n    return;\n  }\n\n  if (menu_get_item()) {\n    // Path is valid (i.e. not 404).\n    return;\n  }\n\n  $callback = 'restful_deliver_menu_not_found';\n}\n\n/**\n * Delivers a not found (404) error.\n */\nfunction restful_deliver_menu_not_found($page_callback_result) {\n  restful_delivery(MENU_NOT_FOUND);\n}\n\n/**\n * Implements hook_cron().\n */\nfunction restful_cron() {\n  \\Drupal\\restful\\RateLimit\\RateLimitManager::deleteExpired();\n}\n\n/**\n * Page callback: returns a session token for the currently active user.\n */\nfunction restful_csrf_session_token() {\n  return array('X-CSRF-Token' => drupal_get_token(\\Drupal\\restful\\Plugin\\authentication\\Authentication::TOKEN_VALUE));\n}\n\n/**\n * Element validate \\DateTime format function.\n */\nfunction restful_date_time_format_element_validate($element, &$form_state) {\n  $value = $element['#value'];\n  try {\n    new \\DateInterval($value);\n  }\n  catch (\\Exception $e) {\n    form_error($element, t('%name must be compatible with the !link.', array(\n      '%name' => $element['#title'],\n      '!link' => l(t('\\DateInterval format'), 'http://php.net/manual/en/class.dateinterval.php'),\n    )));\n  }\n}\n\n/**\n * Implements hook_restful_resource_alter().\n *\n * Decorate an existing resource with other services (e.g. rate limit and render\n * cache).\n */\nfunction restful_restful_resource_alter(ResourceInterface &$resource) {\n  // Disable any plugin in the disabled plugins variable.\n  $disabled_plugins = array(\n    // Disable the Files Upload resource based on the settings variable.\n    'files_upload:1.0' => (bool) !variable_get('restful_file_upload', FALSE),\n    // Disable the Users resources based on the settings variable.\n    'users:1.0' => (bool) !variable_get('restful_enable_users_resource', TRUE),\n    // Disable the Login Cookie resources based on the settings variable.\n    'login_cookie:1.0' => (bool) !variable_get('restful_enable_user_login_resource', TRUE),\n    // Disable the Discovery resource based on the settings variable.\n    'discovery:1.0' => (bool) !variable_get('restful_enable_discovery_resource', TRUE),\n  ) + variable_get('restful_disabled_plugins', array());\n  if (!empty($disabled_plugins[$resource->getResourceName()])) {\n    $resource->disable();\n  }\n  elseif (\n    isset($disabled_plugins[$resource->getResourceName()]) &&\n    $disabled_plugins[$resource->getResourceName()] === FALSE &&\n    !$resource->isEnabled()\n  ) {\n    $resource->enable();\n  }\n\n  $plugin_definition = $resource->getPluginDefinition();\n\n  // If render cache is enabled for the current resource, or there is no render\n  // cache information for the resource but render cache is enabled globally,\n  // then decorate the resource with cache capabilities.\n  if (\n    !empty($plugin_definition['renderCache']['render']) ||\n    (!isset($plugin_definition['renderCache']['render']) && variable_get('restful_render_cache', FALSE))\n  ) {\n    $resource = new CacheDecoratedResource($resource);\n  }\n  // Check for the rate limit configuration.\n  if (!empty($plugin_definition['rateLimit']) || variable_get('restful_global_rate_limit', 0)) {\n    $resource = new RateLimitDecoratedResource($resource);\n  }\n\n  // Disable the discovery endpoint if it's disabled.\n  if (\n    $resource->getResourceMachineName() == 'discovery' &&\n    !variable_get('restful_enable_discovery_resource', TRUE) &&\n    $resource->isEnabled()\n  ) {\n    $resource->disable();\n  }\n}\n"
  },
  {
    "path": "src/Annotation/Authentication.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Annotation\\RateLimit.\n */\n\nnamespace Drupal\\restful\\Annotation;\n\nuse Drupal\\Component\\Annotation\\Plugin;\n\n/**\n * Defines a RateLimit annotation object.\n *\n * @ingroup plug_example_api\n *\n * @Annotation\n */\nclass Authentication extends Plugin {\n\n  /**\n   * The human readable name.\n   *\n   * @var string\n   */\n  public $label;\n\n  /**\n   * The description.\n   *\n   * @var string\n   */\n  public $description;\n\n  /**\n   * Extra options\n   *\n   * @var array\n   */\n  public $options;\n}\n"
  },
  {
    "path": "src/Annotation/Formatter.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Annotation\\Formatter.\n */\n\nnamespace Drupal\\restful\\Annotation;\n\nuse Drupal\\Component\\Annotation\\Plugin;\n\n/**\n * Defines a Formatter annotation object.\n *\n * @ingroup plug_example_api\n *\n * @Annotation\n */\nclass Formatter extends Plugin {\n\n  /**\n   * The human readable name.\n   *\n   * @var string\n   */\n  public $label;\n\n  /**\n   * The description.\n   *\n   * @var string\n   */\n  public $description;\n\n  /**\n   * Information about the curie\n   *\n   * @var array\n   */\n  public $curie;\n\n}\n"
  },
  {
    "path": "src/Annotation/RateLimit.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Annotation\\RateLimit.\n */\n\nnamespace Drupal\\restful\\Annotation;\n\nuse Drupal\\Component\\Annotation\\Plugin;\n\n/**\n * Defines a RateLimit annotation object.\n *\n * @ingroup plug_example_api\n *\n * @Annotation\n */\nclass RateLimit extends Plugin {\n\n  /**\n   * The human readable name.\n   *\n   * @var string\n   */\n  public $label;\n\n  /**\n   * The description.\n   *\n   * @var string\n   */\n  public $description;\n\n}\n"
  },
  {
    "path": "src/Annotation/Resource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Annotation\\Resource.\n */\n\nnamespace Drupal\\restful\\Annotation;\n\nuse Drupal\\Component\\Annotation\\Plugin;\n\n/**\n * Defines a Resource annotation object.\n *\n * @ingroup resource_api\n *\n * @Annotation\n */\nclass Resource extends Plugin {\n\n  /**\n   * Major version.\n   *\n   * @var int\n   */\n  public $majorVersion = 1;\n\n  /**\n   * Minor version.\n   *\n   * @var int\n   */\n  public $minorVersion = 0;\n\n  /**\n   * Resource name.\n   *\n   * @var string\n   */\n  public $name;\n\n  /**\n   * Resource.\n   *\n   * This is used for the resource URL.\n   *\n   * @var string\n   */\n  public $resource;\n\n  /**\n   * Formatter.\n   *\n   * @var string\n   */\n  public $formatter;\n\n  /**\n   * Description.\n   *\n   * @var string\n   */\n  public $description = '';\n\n  /**\n   * Authentication types.\n   *\n   * @var array|bool\n   */\n  public $authenticationTypes = array();\n\n  /**\n   * Authentication optional.\n   *\n   * @var bool\n   */\n  public $authenticationOptional = FALSE;\n\n  /**\n   * Data provider options.\n   *\n   * Contains all the information for the data provider.\n   *\n   * @var array\n   */\n  public $dataProvider = array();\n\n  /**\n   * Cache render.\n   *\n   * Cache render options.\n   *\n   * @var array|bool\n   */\n  public $renderCache = array();\n\n  /**\n   * Hook menu. TRUE if the resource should declare a menu item automatically.\n   *\n   * @var bool\n   */\n  public $hookMenu = TRUE;\n\n  /**\n   * The path to be used as the menu item.\n   *\n   * Leave it empty to create one automatically.\n   *\n   * @var string\n   */\n  public $hookItem;\n\n  /**\n   * Autocomplete options.\n   *\n   * 'string' => 'foo',\n   * 'operator' => 'STARTS_WITH',\n   *\n   * @var array\n   */\n  public $autocomplete = array();\n\n  /**\n   * Access control using the HTTP Access-Control-Allow-Origin header.\n   *\n   * @var string\n   */\n  public $allowOrigin;\n\n  /**\n   * Determines if a resource should be discoverable, and appear under /api.\n   *\n   * @var bool\n   */\n  public $discoverable = TRUE;\n\n  /**\n   * URL parameters.\n   *\n   * @var array\n   */\n  public $urlParams = array();\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getId() {\n    // The ID of the resource plugin is its name.\n    return $this->definition['name'];\n  }\n\n}\n"
  },
  {
    "path": "src/Authentication/AuthenticationManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Authentication\\AuthenticationManager\n */\n\nnamespace Drupal\\restful\\Authentication;\n\nuse Drupal\\restful\\Exception\\UnauthorizedException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\AuthenticationPluginManager;\nuse Drupal\\restful\\RestfulManager;\n\n/**\n * Class AuthenticationManager.\n *\n * @package Drupal\\restful\\Authentication\n */\nclass AuthenticationManager implements AuthenticationManagerInterface {\n\n  /**\n   * The resolved user object.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * The authentication plugins.\n   *\n   * @var AuthenticationPluginCollection\n   */\n  protected $plugins;\n\n  /**\n   * Determines if authentication is optional.\n   *\n   * If FALSE, then UnauthorizedException is thrown if no authentication\n   * was found. Defaults to FALSE.\n   *\n   * @var bool\n   */\n  protected $isOptional = FALSE;\n\n  /**\n   * User session state to switch user for the Drupal thread.\n   *\n   * @var UserSessionStateInterface\n   */\n  protected $userSessionState;\n\n  /**\n   * Constructs a new AuthenticationManager object.\n   *\n   * @param AuthenticationPluginManager $manager\n   *   The authentication plugin manager.\n   */\n  public function __construct(AuthenticationPluginManager $manager = NULL, UserSessionStateInterface $user_session_state = NULL) {\n    $this->plugins = new AuthenticationPluginCollection($manager ?: AuthenticationPluginManager::create());\n    $this->userSessionState = $user_session_state ?: new UserSessionState();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setIsOptional($is_optional) {\n    $this->isOptional = $is_optional;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIsOptional() {\n    return $this->isOptional;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addAuthenticationProvider($plugin_id) {\n    $manager = AuthenticationPluginManager::create();\n    $instance = $manager->createInstance($plugin_id);\n    // The get method will instantiate a plugin if not there.\n    $this->plugins->setInstanceConfiguration($plugin_id, $manager->getDefinition($plugin_id));\n    $this->plugins->set($plugin_id, $instance);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addAllAuthenticationProviders() {\n    $manager = AuthenticationPluginManager::create();\n    foreach ($manager->getDefinitions() as $id => $plugin) {\n      $this->addAuthenticationProvider($id);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount(RequestInterface $request, $cache = TRUE) {\n    global $user;\n    // Return the previously resolved user, if any.\n    if (!empty($this->account)) {\n      return $this->account;\n    }\n    // Resolve the user based on the providers in the manager.\n    $account = NULL;\n    foreach ($this->plugins as $provider) {\n      /* @var \\Drupal\\restful\\Plugin\\authentication\\AuthenticationInterface $provider */\n      if ($provider->applies($request) && ($account = $provider->authenticate($request)) && $account->uid && $account->status) {\n        // The account has been loaded, we can stop looking.\n        break;\n      }\n    }\n\n    if (empty($account->uid) || !$account->status) {\n\n      if (RestfulManager::isRestfulPath($request) && $this->plugins->count() && !$this->getIsOptional()) {\n        // Allow caching pages for anonymous users.\n        drupal_page_is_cacheable(variable_get('restful_page_cache', FALSE));\n\n        // User didn't authenticate against any provider, so we throw an error.\n        throw new UnauthorizedException('Bad credentials. Anonymous user resolved for a resource that requires authentication.');\n      }\n\n      // If the account could not be authenticated default to the global user.\n      // Most of the cases the cookie provider will do this for us.\n      $account = drupal_anonymous_user();\n\n      if (!$request->isViaRouter()) {\n        // If we are using the API from within Drupal and we have not tried to\n        // authenticate using the 'cookie' provider, then we expect to be logged\n        // in using the cookie authentication as a last resort.\n        $account = $user->uid ? user_load($user->uid) : $account;\n      }\n    }\n    if ($cache) {\n      $this->setAccount($account);\n    }\n    // Disable page caching for security reasons so that an authenticated user\n    // response never gets into the page cache for anonymous users.\n    // This is necessary because the page cache system only looks at session\n    // cookies, but not at HTTP Basic Auth headers.\n    drupal_page_is_cacheable(!$account->uid && variable_get('restful_page_cache', FALSE));\n\n    // Record the access time of this request.\n    $this->setAccessTime($account);\n\n    return $account;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->account = $account;\n    if (!empty($account->uid)) {\n      $this->userSessionState->switchUser($account);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function switchUserBack() {\n    return $this->userSessionState->switchUserBack();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPlugins() {\n    return $this->plugins;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPlugin($instance_id) {\n    return $this->plugins->get($instance_id);\n  }\n\n  /**\n   * Set the user's last access time.\n   *\n   * @param object $account\n   *   A user account.\n   *\n   * @see _drupal_session_write()\n   */\n  protected function setAccessTime($account) {\n    // This logic is pulled directly from _drupal_session_write().\n    if ($account->uid && REQUEST_TIME - $account->access > variable_get('session_write_interval', 180)) {\n      db_update('users')->fields(array(\n        'access' => REQUEST_TIME,\n      ))->condition('uid', $account->uid)->execute();\n    }\n  }\n\n}\n"
  },
  {
    "path": "src/Authentication/AuthenticationManagerInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Authentication\\AuthenticationManagerInterface\n */\n\nnamespace Drupal\\restful\\Authentication;\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse \\Drupal\\restful\\Exception\\UnauthorizedException;\nuse \\Drupal\\restful\\Plugin\\Authentication\\AuthenticationInterface;\nuse \\Drupal\\restful\\Plugin\\AuthenticationPluginManager;\nuse \\Drupal\\restful\\Http\\RequestInterface;\n\ninterface AuthenticationManagerInterface {\n\n  /**\n   * Set the authentications' \"optional\" flag.\n   *\n   * @param boolean $is_optional\n   *   Determines if the authentication is optional.\n   */\n  public function setIsOptional($is_optional);\n\n  /**\n   * Get the authentications' \"optional\" flag.\n   *\n   * @return boolean\n   *   TRUE if the authentication is optional.\n   */\n  public function getIsOptional();\n\n  /**\n   * Adds the auth provider to the list.\n   *\n   * @param string $plugin_id\n   *   The authentication plugin id.\n   */\n  public function addAuthenticationProvider($plugin_id);\n\n  /**\n   * Adds all the auth providers to the list.\n   */\n  public function addAllAuthenticationProviders();\n\n  /**\n   * Get the user account for the request.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   * @param bool $cache\n   *   Boolean indicating if the resolved user should be cached for next calls.\n   *\n   * @throws UnauthorizedException\n   *   When bad credentials are provided.\n   *\n   * @return object\n   *   The user object.\n   */\n  public function getAccount(RequestInterface $request, $cache = TRUE);\n\n  /**\n   * Setter method for the account property.\n   *\n   * @param object $account\n   *   The account to set.\n   */\n  public function setAccount($account);\n\n  /**\n   * Switches the user back from the original user for the session.\n   */\n  public function switchUserBack();\n\n  /**\n   * Gets the plugin collection for this plugin manager.\n   *\n   * @return AuthenticationPluginManager\n   *   The plugin manager.\n   */\n  public function getPlugins();\n\n  /**\n   * Get an authentication plugin instance by instance ID.\n   *\n   * @param string $instance_id\n   *   The instance ID.\n   *\n   * @return AuthenticationInterface\n   *   The plugin.\n   *\n   * @throws PluginNotFoundException\n   *   If the plugin instance cannot be found.\n   */\n  public function getPlugin($instance_id);\n\n}\n"
  },
  {
    "path": "src/Authentication/AuthenticationPluginCollection.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Authentication\\AuthenticationPluginCollection\n */\n\nnamespace Drupal\\restful\\Authentication;\n\nuse Drupal\\Core\\Plugin\\DefaultLazyPluginCollection;\n\nclass AuthenticationPluginCollection extends DefaultLazyPluginCollection {}\n"
  },
  {
    "path": "src/Authentication/UserSessionState.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Authentication\\UserSessionState.\n */\n\nnamespace Drupal\\restful\\Authentication;\n\n/**\n * Class UserSessionState.\n *\n * @package Drupal\\restful\\Authentication\n */\nclass UserSessionState implements UserSessionStateInterface {\n\n  /**\n   * Boolean holding if this is the first switch.\n   *\n   * @var bool\n   */\n  protected static $isSwitched = FALSE;\n\n  /**\n   * Boolean holding if the session needs to be saved.\n   *\n   * @var bool\n   */\n  protected $needsSaving = FALSE;\n\n  /**\n   * Object holding the original user.\n   *\n   * This is saved for switch back purposes.\n   *\n   * @var object\n   */\n  protected $originalUser;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isSwitched() {\n    return static::$isSwitched;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function switchUser($account) {\n    global $user;\n\n    if (!static::isSwitched() && !$this->originalUser && !$this->needsSaving) {\n      // This is the first time a user switched, and there isn't an original\n      // user session.\n      $this->needsSaving = drupal_save_session();\n      $this->originalUser = $user;\n\n      // Don't allow a session to be saved. Provider that require a session to\n      // be saved, like the cookie provider, need to explicitly set\n      // drupal_save_session(TRUE).\n      // @see LoginCookie__1_0::loginUser().\n      drupal_save_session(FALSE);\n    }\n\n    // Set the global user.\n    $user = $account;\n  }\n\n  /**\n   * Switch the user to the authenticated user, and back.\n   *\n   * This should be called only for an API call. It should not be used for calls\n   * via the menu system, as it might be a login request, so we avoid switching\n   * back to the anonymous user.\n   */\n  public function switchUserBack() {\n    global $user;\n    if (!$this->originalUser) {\n      return;\n    }\n\n    $user = $this->originalUser;\n    drupal_save_session($this->needsSaving);\n    $this->reset();\n  }\n\n  /**\n   * Reset the initial values.\n   */\n  protected function reset() {\n    // Reset initial values.\n    static::$isSwitched = FALSE;\n    $this->originalUser = NULL;\n    $this->needsSaving = FALSE;\n  }\n\n}\n"
  },
  {
    "path": "src/Authentication/UserSessionStateInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Authentication\\UserSessionStateInterface.\n */\n\nnamespace Drupal\\restful\\Authentication;\n\n/**\n * Class UserSessionStateInterface.\n *\n * @package Drupal\\restful\\Authentication\n */\ninterface UserSessionStateInterface {\n\n  /**\n   * Check if the user has already been switched.\n   *\n   * We need this information to perform additional actions the first time a\n   * user is switched.\n   *\n   * @return bool\n   *   TRUE if the user has been switched previously. FALSE otherwise.\n   */\n  public static function isSwitched();\n\n  /**\n   * Make the passed in user to be the account for the Drupal thread.\n   *\n   * @param object $account\n   *   The account to switch to.\n   */\n  public function switchUser($account);\n\n  /**\n   * Switch the user to the authenticated user, and back.\n   *\n   * This should be called only for an API call. It should not be used for calls\n   * via the menu system, as it might be a login request, so we avoid switching\n   * back to the anonymous user.\n   */\n  public function switchUserBack();\n\n}\n"
  },
  {
    "path": "src/Exception/BadRequestException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\BadRequestException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass BadRequestException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 400;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-bad-request';\n\n}\n"
  },
  {
    "path": "src/Exception/FloodException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\FloodException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass FloodException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 429;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-flood';\n\n}\n"
  },
  {
    "path": "src/Exception/ForbiddenException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\ForbiddenException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass ForbiddenException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 403;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-forbidden';\n\n}\n"
  },
  {
    "path": "src/Exception/GoneException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\GoneException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass GoneException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 410;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $description = 'The resource at this end point is no longer available.';\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-gone';\n\n}\n"
  },
  {
    "path": "src/Exception/InaccessibleRecordException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\InaccessibleRecordException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\n/**\n * Class InaccessibleRecordException.\n *\n * @package Drupal\\restful\\Exception\n */\nclass InaccessibleRecordException extends RestfulException {\n\n  const ERROR_404_MESSAGE = 'Page not found.';\n\n  /**\n   * Instantiates a InaccessibleRecordException object.\n   *\n   * @param string $message\n   *   The exception message.\n   */\n  public function __construct($message) {\n    $show_access_denied = variable_get('restful_show_access_denied', FALSE);\n    $this->message = $show_access_denied ? $message : static::ERROR_404_MESSAGE;\n    $this->code = $show_access_denied ? 403 : 404;\n    $this->instance = $show_access_denied ? 'help/restful/problem-instances-forbidden' : 'help/restful/problem-instances-not-found';\n  }\n\n}\n"
  },
  {
    "path": "src/Exception/IncompatibleFieldDefinitionException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\IncompatibleFieldDefinitionException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass IncompatibleFieldDefinitionException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 500;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $description = 'Incompatible field definition.';\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-incompatible-field-definition';\n\n}\n"
  },
  {
    "path": "src/Exception/InternalServerErrorException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\InternalServerErrorException\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass InternalServerErrorException extends RestfulException {\n\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 500;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-server-configuration';\n\n}\n"
  },
  {
    "path": "src/Exception/NotFoundException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\NotFoundException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass NotFoundException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 404;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-not-found';\n\n}\n"
  },
  {
    "path": "src/Exception/NotImplementedException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\NotImplementedException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass NotImplementedException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 501;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-not-implemented';\n\n}\n"
  },
  {
    "path": "src/Exception/RestfulException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\RestfulException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nuse Drupal\\restful\\Http\\Response;\n\nclass RestfulException extends \\Exception {\n\n  /**\n   * Defines the instance resource.\n   *\n   * @var string\n   */\n  protected $instance = NULL;\n\n  /**\n   * Array keyed by the field name, and array of error messages as value.\n   *\n   * @var array\n   */\n  protected $fieldErrors = array();\n\n  /**\n   * Array of extra headers to set when throwing an exception.\n   *\n   * @var array\n   */\n  protected $headers = array();\n\n  /**\n   * Exception description.\n   *\n   * @var string\n   */\n  protected $description = '';\n\n  /**\n   * Gets the description of the exception.\n   *\n   * @return string\n   *   The description.\n   */\n  final public function getDescription() {\n    return $this->description ? $this->description : Response::$statusTexts[$this->getCode()];\n  }\n\n  /**\n   * Return a string to the common problem type.\n   *\n   * @return string\n   *   URL pointing to the specific RFC-2616 section.\n   */\n  public function getType() {\n    // Depending on the error code we'll return a different URL.\n    $url = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html';\n    $sections = array(\n      '100' => '#sec10.1.1',\n      '101' => '#sec10.1.2',\n      '200' => '#sec10.2.1',\n      '201' => '#sec10.2.2',\n      '202' => '#sec10.2.3',\n      '203' => '#sec10.2.4',\n      '204' => '#sec10.2.5',\n      '205' => '#sec10.2.6',\n      '206' => '#sec10.2.7',\n      '300' => '#sec10.3.1',\n      '301' => '#sec10.3.2',\n      '302' => '#sec10.3.3',\n      '303' => '#sec10.3.4',\n      '304' => '#sec10.3.5',\n      '305' => '#sec10.3.6',\n      '307' => '#sec10.3.8',\n      '400' => '#sec10.4.1',\n      '401' => '#sec10.4.2',\n      '402' => '#sec10.4.3',\n      '403' => '#sec10.4.4',\n      '404' => '#sec10.4.5',\n      '405' => '#sec10.4.6',\n      '406' => '#sec10.4.7',\n      '407' => '#sec10.4.8',\n      '408' => '#sec10.4.9',\n      '409' => '#sec10.4.10',\n      '410' => '#sec10.4.11',\n      '411' => '#sec10.4.12',\n      '412' => '#sec10.4.13',\n      '413' => '#sec10.4.14',\n      '414' => '#sec10.4.15',\n      '415' => '#sec10.4.16',\n      '416' => '#sec10.4.17',\n      '417' => '#sec10.4.18',\n      '500' => '#sec10.5.1',\n      '501' => '#sec10.5.2',\n      '502' => '#sec10.5.3',\n      '503' => '#sec10.5.4',\n      '504' => '#sec10.5.5',\n      '505' => '#sec10.5.6',\n    );\n    return empty($sections[$this->getCode()]) ? $url : $url . $sections[$this->getCode()];\n  }\n\n  /**\n   * Get the URL to the error for the particular case.\n   *\n   * @return string\n   *   The url or NULL if empty.\n   */\n  public function getInstance() {\n    // Handle all instances using the advanced help module.\n    if (!module_exists('advanced_help') || empty($this->instance)) {\n      return NULL;\n    }\n    return url($this->instance, array(\n      'absolute' => TRUE,\n    ));\n  }\n\n  /**\n   * Return an array with all the errors.\n   */\n  public function getFieldErrors() {\n    return $this->fieldErrors;\n  }\n\n  /**\n   * Add an error per field.\n   *\n   * @param string $field_name\n   *   The field name.\n   * @param string $error_message\n   *   The error message.\n   */\n  public function addFieldError($field_name, $error_message) {\n    $this->fieldErrors[$field_name][] = $error_message;\n  }\n\n  /**\n   * Get the associative array of headers.\n   *\n   * @return array\n   *   The associated headers to the error exception.\n   */\n  public function getHeaders() {\n    return $this->headers;\n  }\n\n  /**\n   * Set a header.\n   *\n   * @param string $key\n   *   The header name.\n   * @param string $value\n   *   The header value.\n   */\n  public function setHeader($key, $value) {\n    $this->headers[$key] = $value;\n  }\n\n}\n"
  },
  {
    "path": "src/Exception/ServerConfigurationException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\ServerConfigurationException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass ServerConfigurationException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 500;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $description = 'Server configuration error.';\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-server-configuration';\n\n}\n"
  },
  {
    "path": "src/Exception/ServiceUnavailableException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\ServiceUnavailable.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass ServiceUnavailableException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 503;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-bad-request';\n\n}\n"
  },
  {
    "path": "src/Exception/UnauthorizedException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\UnauthorizedException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass UnauthorizedException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 401;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-unauthorized';\n\n}\n"
  },
  {
    "path": "src/Exception/UnprocessableEntityException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\UnprocessableEntityException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass UnprocessableEntityException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 422;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $description = 'Unprocessable Entity; Validation errors.';\n\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-unprocessable-entity';\n\n}\n"
  },
  {
    "path": "src/Exception/UnsupportedMediaTypeException.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Exception\\UnsupportedMediaTypeException.\n */\n\nnamespace Drupal\\restful\\Exception;\n\nclass UnsupportedMediaTypeException extends RestfulException {\n\n  /**\n   * Defines the HTTP error code.\n   *\n   * @var int\n   */\n  protected $code = 415;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $instance = 'help/restful/problem-instances-unsupported-media-type';\n\n}\n"
  },
  {
    "path": "src/Formatter/FormatterManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Formatter\\FormatterManager\n */\n\nnamespace Drupal\\restful\\Formatter;\n\nuse Drupal\\restful\\Exception\\ServiceUnavailableException;\nuse Drupal\\restful\\Http\\HttpHeader;\nuse Drupal\\restful\\Plugin\\formatter\\FormatterInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\FormatterPluginManager;\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\n/**\n * Class FormatterManager.\n *\n * @package Drupal\\restful\\Formatter\n */\nclass FormatterManager implements FormatterManagerInterface {\n\n  /**\n   * The rate limit plugins.\n   *\n   * @var FormatterPluginCollection\n   */\n  protected $plugins;\n\n  /**\n   * The resource.\n   *\n   * @todo: Remove this coupling.\n   *\n   * @var ResourceInterface\n   */\n  protected $resource;\n\n  /**\n   * Constructs FormatterManager.\n   *\n   * @param ResourceInterface $resource\n   *   TODO: Remove this coupling.\n   *   The resource.\n   */\n  public function __construct($resource = NULL) {\n    $this->resource = $resource;\n    $manager = FormatterPluginManager::create();\n    $options = array();\n    foreach ($manager->getDefinitions() as $plugin_id => $plugin_definition) {\n      // Since there is only one instance per plugin_id use the plugin_id as\n      // instance_id.\n      $options[$plugin_id] = $plugin_definition;\n    }\n    $this->plugins = new FormatterPluginCollection($manager, $options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResource($resource) {\n    $this->resource = $resource;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function format(array $data, $formatter_name = NULL) {\n    return $this->processData('format', $data, $formatter_name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(array $data, $formatter_name = NULL) {\n    return $this->processData('render', $data, $formatter_name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function negotiateFormatter($accept, $formatter_name = NULL) {\n    $message = 'Formatter plugin class was not found.';\n    $default_formatter_name = variable_get('restful_default_output_formatter', 'json');\n    try {\n      if ($formatter_name) {\n        return $this->getPluginByName($formatter_name);\n      }\n      // Sometimes we will get a default Accept: */* in that case we want to\n      // return the default content type and not just any.\n      if (empty($accept) || $accept == '*/*') {\n        // Return the default formatter.\n        return $this->getPluginByName($default_formatter_name);\n      }\n      foreach (explode(',', $accept) as $accepted_content_type) {\n        // Loop through all the formatters and find the first one that matches\n        // the Content-Type header.\n        $accepted_content_type = trim($accepted_content_type);\n        if (strpos($accepted_content_type, '*/*') === 0) {\n          return $this->getPluginByName($default_formatter_name);\n        }\n        foreach ($this->plugins as $formatter_name => $formatter) {\n          /* @var FormatterInterface $formatter */\n          if (static::matchContentType($formatter->getContentTypeHeader(), $accepted_content_type)) {\n            $formatter->setConfiguration(array(\n              'resource' => $this->resource,\n            ));\n            return $formatter;\n          }\n        }\n      }\n    }\n    catch (PluginNotFoundException $e) {\n      // Catch the exception and throw one of our own.\n      $message = $e->getMessage();\n    }\n    throw new ServiceUnavailableException($message);\n  }\n\n  /**\n   * Helper function to get a formatter and apply a method.\n   *\n   * @param string $method\n   *   A valid method to call on the FormatterInterface object.\n   * @param array $data\n   *   The array of data to process.\n   * @param string $formatter_name\n   *   The name of the formatter for the current resource. Leave it NULL to use\n   *   the Accept headers.\n   *\n   * @return string\n   *   The processed output.\n   */\n  protected function processData($method, array $data, $formatter_name = NULL) {\n    if ($resource = $this->resource) {\n      $request = $resource->getRequest();\n    }\n    else {\n      $request = restful()->getRequest();\n    }\n    $accept = $request\n      ->getHeaders()\n      ->get('accept')\n      ->getValueString();\n    $formatter = $this->negotiateFormatter($accept, $formatter_name);\n    $output = ResourceManager::executeCallback(array($formatter, $method), array($data, $formatter_name));\n\n    // The content type header is modified after the massaging if there is\n    // an error code. Therefore we need to set the content type header after\n    // formatting the output.\n    $content_type = $formatter->getContentTypeHeader();\n    $response_headers = restful()\n      ->getResponse()\n      ->getHeaders();\n    $response_headers->add(HttpHeader::create('Content-Type', $content_type));\n\n    return $output;\n  }\n\n  /**\n   * Matches a string with path style wildcards.\n   *\n   * @param string $content_type\n   *   The string to check.\n   * @param string $pattern\n   *   The pattern to check against.\n   *\n   * @return bool\n   *   TRUE if the input matches the pattern.\n   *\n   * @see drupal_match_path().\n   */\n  protected static function matchContentType($content_type, $pattern) {\n    $regexps = &drupal_static(__METHOD__);\n\n    if (!isset($regexps[$pattern])) {\n      // Convert path settings to a regular expression.\n      $to_replace = array(\n        '/\\\\\\\\\\*/', // asterisks\n      );\n      $replacements = array(\n        '.*',\n      );\n      $patterns_quoted = preg_quote($pattern, '/');\n\n      // This will turn 'application/*' into '/^(application\\/.*)(;.*)$/'\n      // allowing us to match 'application/json; charset: utf8'\n      $regexps[$pattern] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')(;.*)?$/i';\n    }\n    return (bool) preg_match($regexps[$pattern], $content_type);\n  }\n\n  /**\n   * {@inheritdocs}\n   */\n  public function getPlugins() {\n    return $this->plugins;\n  }\n\n  /**\n   * {@inheritdocs}\n   */\n  public function getPlugin($instance_id) {\n    return $this->plugins->get($instance_id);\n  }\n\n  /**\n   * Gets a plugin by name initializing the resource.\n   *\n   * @param string $name\n   *   The formatter name.\n   *\n   * @return FormatterInterface\n   *   The plugin.\n   */\n  protected function getPluginByName($name) {\n    /* @var FormatterInterface $formatter */\n    $formatter = $this->plugins->get($name);\n    if ($this->resource) {\n      $formatter->setResource($this->resource);\n    }\n    return $formatter;\n  }\n\n}\n"
  },
  {
    "path": "src/Formatter/FormatterManagerInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Formatter\\FormatterManagerInterface\n */\n\nnamespace Drupal\\restful\\Formatter;\n\nuse Drupal\\restful\\Plugin\\formatter\\FormatterInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\ninterface FormatterManagerInterface {\n\n  /**\n   * Sets the resource.\n   *\n   * @param ResourceInterface $resource\n   *   The resource.\n   */\n  public function setResource($resource);\n\n  /**\n   * Call the output format on the given data.\n   *\n   * @param array $data\n   *   The array of data to format.\n   * @param string $formatter_name\n   *   The name of the formatter for the current resource. Leave it NULL to use\n   *   the Accept headers.\n   *\n   * @return string\n   *   The formatted output.\n   */\n  public function format(array $data, $formatter_name = NULL);\n\n  /**\n   * Call the output format on the given data.\n   *\n   * @param array $data\n   *   The array of data to render.\n   * @param string $formatter_name\n   *   The name of the formatter for the current resource. Leave it NULL to use\n   *   the Accept headers.\n   *\n   * @return string\n   *   The rendered output.\n   */\n  public function render(array $data, $formatter_name = NULL);\n\n  /**\n   * Helper function to get the default output format from the current request.\n   *\n   * @param string $accept\n   *   The Accept header.\n   * @param string $formatter_name\n   *   The name of the formatter for the current resource.\n   *\n   * @return FormatterInterface\n   *   The formatter plugin to use.\n   */\n  public function negotiateFormatter($accept, $formatter_name = NULL);\n\n  /**\n   * Returns the plugins.\n   *\n   * @return FormatterPluginCollection\n   */\n  public function getPlugins();\n\n  /**\n   * Returns the plugin instance for the given instance ID.\n   *\n   * @return FormatterInterface\n   */\n  public function getPlugin($instance_id);\n\n}\n"
  },
  {
    "path": "src/Formatter/FormatterPluginCollection.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Formatter\\FormatterPluginCollection\n */\n\nnamespace Drupal\\restful\\Formatter;\n\nuse Drupal\\Core\\Plugin\\DefaultLazyPluginCollection;\n\nclass FormatterPluginCollection extends DefaultLazyPluginCollection {}\n"
  },
  {
    "path": "src/Http/HttpHeader.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\HttpHeader\n */\n\nnamespace Drupal\\restful\\Http;\n\nclass HttpHeader implements HttpHeaderInterface {\n\n  /**\n   * Header ID.\n   *\n   * @var string\n   */\n  protected $id;\n\n  /**\n   * Header name.\n   *\n   * @var string\n   */\n  protected $name;\n\n  /**\n   * Header values.\n   *\n   * @var array\n   */\n  protected $values = array();\n\n  /**\n   * Header extras.\n   *\n   * @var string\n   */\n  protected $extras;\n\n  /**\n   * Constructor.\n   */\n  public function __construct($name, array $values, $extras) {\n    $this->name = $name;\n    $this->id = static::generateId($name);\n    $this->values = $values;\n    $this->extras = $extras;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create($key, $value) {\n    list($extras, $values) = self::parseHeaderValue($value);\n    return new static($key, $values, $extras);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get() {\n    return $this->values;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getValueString() {\n    $parts = array();\n    $parts[] = implode(', ', $this->values);\n    $parts[] = $this->extras;\n    return implode('; ', array_filter($parts));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getName() {\n    return $this->name;\n  }\n\n  /**\n   * Returns the string version of the header.\n   *\n   * @return string\n   */\n  public function __toString() {\n    return $this->name . ': ' . $this->getValueString();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($values) {\n    $this->values = $values;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function append($value) {\n    // Ignore the extras.\n    list(, $values) = static::parseHeaderValue($value);\n    foreach ($values as $value) {\n      $this->values[] = $value;\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getId() {\n    return $this->id;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function generateId($name) {\n    return strtolower($name);\n  }\n\n  /**\n   * Parses the values and extras from a header value string.\n   *\n   * @param string $value\n   *\n   * @return array\n   *   The $extras and $values.\n   */\n  protected static function parseHeaderValue($value) {\n    $extras = NULL;\n    $parts = explode(';', $value);\n    if (count($parts) > 1) {\n      // Only consider the last element.\n      $extras = array_pop($parts);\n      $extras = trim($extras);\n      // In case there were more than one ';' then put everything back.\n      $value = implode(';', $parts);\n    }\n    $values = array_map('trim', explode(',', $value));\n    return array($extras, $values);\n  }\n\n}\n"
  },
  {
    "path": "src/Http/HttpHeaderBag.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\HttpHeaderBag.\n */\n\nnamespace Drupal\\restful\\Http;\n\nclass HttpHeaderBag implements HttpHeaderBagInterface, \\Iterator {\n\n  /**\n   * The header objects keyed by ID.\n   *\n   * @var array\n   */\n  protected $values = array();\n\n  /**\n   * Constructor\n   *\n   * @param array $headers\n   *   Array of key value pairs.\n   */\n  public function __construct($headers = array()) {\n    foreach ($headers as $key => $value) {\n      $header = HttpHeader::create($key, $value);\n      $this->values[$header->getId()] = $header;\n    }\n  }\n\n  /**\n   * Returns the header bag as a string.\n   *\n   * @return string\n   *   The string representation.\n   */\n  public function __toString() {\n    $headers = array();\n    foreach ($this->values as $key => $header) {\n      /* @var HttpHeader $header */\n      $headers[] = $header->__toString();\n    }\n    return implode(\"\\r\\n\", $headers);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get($key) {\n    // Assume that $key is an ID.\n    if (array_key_exists($key, $this->values)) {\n      return $this->values[$key];\n    }\n    // Test if key was a header name.\n    $key = HttpHeader::generateId($key);\n    if (array_key_exists($key, $this->values)) {\n      return $this->values[$key];\n    }\n    // Return a NULL object on which you can still call the HttpHeaderInterface\n    // methods.\n    return HttpHeaderNull::create(NULL, NULL);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function has($key) {\n    return !empty($this->values[$key]);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getValues() {\n    return $this->values;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function add(HttpHeaderInterface $header) {\n    $this->values[$header->getId()] = $header;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function append(HttpHeaderInterface $header) {\n    if (!$this->has($header->getId())) {\n      $this->add($header);\n      return;\n    }\n    $existing_header = $this->get($header->getId());\n    // Append all the values in the passed in header to the existing header\n    // values.\n    foreach ($header->get() as $value) {\n      $existing_header->append($value);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($key) {\n    // Assume that $key is an ID.\n    if (!array_key_exists($key, $this->values)) {\n      // Test if key was a header name.\n      $key = HttpHeader::generateId($key);\n      if (!array_key_exists($key, $this->values)) {\n        return;\n      }\n    }\n    unset($this->values[$key]);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function current() {\n    return current($this->values);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function next() {\n    return next($this->values);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function key() {\n    return key($this->values);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function valid() {\n    $key = key($this->values);\n    return $key !== NULL && $key !== FALSE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function rewind() {\n    return reset($this->values);\n  }\n\n}\n"
  },
  {
    "path": "src/Http/HttpHeaderBagInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\HttpHeaderBagInterface.\n */\n\nnamespace Drupal\\restful\\Http;\n\nuse \\Drupal\\restful\\Exception\\ServerConfigurationException;\n\ninterface HttpHeaderBagInterface {\n\n  /**\n   * Get the the header object for a header name or ID.\n   *\n   * @param string $key\n   *   The header ID or header name.\n   *\n   * @return HttpHeaderInterface\n   *   The header object.\n   */\n  public function get($key);\n\n  /**\n   * Checks the existence of a header in the bag.\n   *\n   * @param string $key\n   *   The header ID or header name.\n   *\n   * @return bool\n   *   TRUE if the header is present. FALSE otherwise.\n   */\n  public function has($key);\n\n  /**\n   * Returns all the headers set on the bag.\n   *\n   * @return array\n   */\n  public function getValues();\n\n  /**\n   * Add a header to the bag.\n   *\n   * @param HttpHeaderInterface $header\n   *   The header object or an associative array with the name and value.\n   *\n   * @throws ServerConfigurationException\n   */\n  public function add(HttpHeaderInterface $header);\n\n  /**\n   * Appends the values of the passed in header to if the header already exists.\n   *\n   * @param HttpHeaderInterface $header\n   *   The header object or an associative array with the name and value.\n   *\n   * @throws ServerConfigurationException\n   */\n  public function append(HttpHeaderInterface $header);\n\n  /**\n   * Removes a header from the bag.\n   *\n   * @param string $key\n   *   The header ID or the header name.\n   */\n  public function remove($key);\n\n}\n"
  },
  {
    "path": "src/Http/HttpHeaderInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\HttpHeaderInterface\n */\n\nnamespace Drupal\\restful\\Http;\n\ninterface HttpHeaderInterface {\n\n  /**\n   * Creates a header object from the key and value strings.\n   *\n   * @param string $key\n   *   The header name.\n   * @param string $value\n   *   The header value.\n   *\n   * @return HttpHeaderInterface\n   *   The parsed header.\n   */\n  public static function create($key, $value);\n\n  /**\n   * Gets the values of the header.\n   *\n   * @return array\n   *   The values for this header.\n   */\n  public function get();\n\n  /**\n   * Gets the contents of the header.\n   *\n   * @return string\n   *   The header value as a string.\n   */\n  public function getValueString();\n\n  /**\n   * Gets the header name.\n   *\n   * @return string\n   */\n  public function getName();\n\n  /**\n   * Sets the values.\n   *\n   * @param array $values\n   *   A numeric array containing all the values for the given header.\n   */\n  public function set($values);\n\n  /**\n   * Appends a value into a header.\n   *\n   * @param string $value\n   *   The string value to append.\n   */\n  public function append($value);\n\n  /**\n   * Gets the header id.\n   *\n   * @return string\n   *   The header ID.\n   */\n  public function getId();\n\n  /**\n   * Generates the header ID based on the header name.\n   *\n   * @param string $name\n   *   The header name.\n   *\n   * @return string\n   *   The ID.\n   */\n  public static function generateId($name);\n\n}\n"
  },
  {
    "path": "src/Http/HttpHeaderNull.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\HttpHeaderNull\n */\n\nnamespace Drupal\\restful\\Http;\n\nclass HttpHeaderNull implements HttpHeaderInterface {\n\n  /**\n   * Header ID.\n   *\n   * @var string\n   */\n  protected $id;\n\n  /**\n   * Header name.\n   *\n   * @var string\n   */\n  protected $name;\n\n  /**\n   * Header values.\n   *\n   * @var array\n   */\n  protected $values = array();\n\n  /**\n   * Header extras.\n   *\n   * @var string\n   */\n  protected $extras;\n\n  /**\n   * Constructor.\n   */\n  public function __construct($name, array $values, $extras) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create($key, $value) {\n    return new static(NULL, array(), NULL);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get() {\n    return $this->values;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getValueString() {\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getName() {\n    return NULL;\n  }\n\n  /**\n   * Returns the string version of the header.\n   *\n   * @return string\n   */\n  public function __toString() {\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($values) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public function append($value) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getId() {\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function generateId($name) {\n    return NULL;\n  }\n\n}\n"
  },
  {
    "path": "src/Http/Request.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\Request\n */\n\nnamespace Drupal\\restful\\Http;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Util\\StringHelper;\n\n/**\n * Deals with everything coming from the consumer.\n */\nclass Request implements RequestInterface {\n\n  /**\n   * Names for headers that can be trusted when\n   * using trusted proxies.\n   *\n   * The default names are non-standard, but widely used\n   * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).\n   */\n  protected static $trustedHeaders = array(\n    self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',\n    self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',\n    self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',\n    self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',\n  );\n\n  protected static $trustedProxies = array();\n\n  /**\n   * HTTP Method.\n   *\n   * @var string\n   */\n  protected $method;\n\n  /**\n   * URI (path and query string).\n   *\n   * @var string\n   */\n  protected $uri;\n\n  /**\n   * Path\n   *\n   * @var string\n   */\n  protected $path;\n\n  /**\n   * Query parameters.\n   *\n   * @var array\n   */\n  protected $query;\n\n  /**\n   * The input HTTP headers.\n   *\n   * @var HttpHeaderBag\n   */\n  protected $headers;\n\n  /**\n   * The unprocessed body of the request.\n   *\n   * This should be a PHP stream, but let's keep it simple.\n   *\n   * @var string\n   */\n  protected $body;\n\n  /**\n   * Indicates if the request was routed by the menu system.\n   *\n   * @var bool\n   */\n  protected $viaRouter = FALSE;\n\n  /**\n   * The passed in CSRF token in the corresponding header.\n   *\n   * @var string\n   */\n  protected $csrfToken = NULL;\n\n  /**\n   * Cookies for the request.\n   *\n   * @var array\n   */\n  protected $cookies = array();\n\n  /**\n   * Files attached to the request.\n   *\n   * @var array\n   */\n  protected $files = array();\n\n  /**\n   * Server information.\n   *\n   * @var array\n   */\n  protected $server = array();\n\n  /**\n   * Holds the parsed body.\n   *\n   * @var array\n   */\n  private $parsedBody;\n\n  /**\n   * Holds the parsed input via URL.\n   *\n   * @internal\n   * @var \\ArrayObject\n   */\n  private $parsedInput;\n\n  /**\n   * Store application data as part of the request.\n   *\n   * @var array\n   */\n  protected $applicationData = array();\n\n  /**\n   * Constructor.\n   *\n   * Parses the URL and the query params. It also uses input:// to get the body.\n   */\n  public function __construct($path, array $query, $method = 'GET', HttpHeaderBag $headers, $via_router = FALSE, $csrf_token = NULL, array $cookies = array(), array $files = array(), array $server = array(), $parsed_body = NULL) {\n    $this->path = $path;\n    $this->query = !isset($query) ? static::parseInput() : $query;\n    $this->query = $this->fixQueryFields($this->query);\n    // If the method is empty, fall back to GET.\n    $this->method = $method ?: static::METHOD_GET;\n    $this->headers = $headers;\n    $this->viaRouter = $via_router;\n    $this->csrfToken = $csrf_token;\n    $this->cookies = $cookies;\n    $this->files = $files;\n    $this->server = $server;\n    $this->parsedBody = $parsed_body;\n\n    // Allow implementing modules to alter the request.\n    drupal_alter('restful_parse_request', $this);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create($path, array $query = array(), $method = 'GET', HttpHeaderBag $headers = NULL, $via_router = FALSE, $csrf_token = NULL, array $cookies = array(), array $files = array(), array $server = array(), $parsed_body = NULL) {\n    if (!$headers) {\n      $headers = new HttpHeaderBag();\n    }\n    if (($overridden_method = strtoupper($headers->get('x-http-method-override')->getValueString())) && ($method == static::METHOD_POST)) {\n      if (!static::isValidMethod($overridden_method)) {\n        throw new BadRequestException(sprintf('Invalid overridden method: %s.', $overridden_method));\n      }\n      $method = $overridden_method;\n    }\n    return new static($path, $query, $method, $headers, $via_router, $csrf_token, $cookies, $files, $server, $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function createFromGlobals() {\n    $path = implode('/', arg());\n    $query =  drupal_get_query_parameters();\n    $method = strtoupper($_SERVER['REQUEST_METHOD']);\n\n    // This flag is used to identify if the request is done \"via Drupal\" or \"via\n    // CURL\";\n    $via_router = TRUE;\n    $headers = static::parseHeadersFromGlobals();\n    $csrf_token = $headers->get('x-csrf-token')->getValueString();\n\n    return static::create($path, $query, $method, $headers, $via_router, $csrf_token, $_COOKIE, $_FILES, $_SERVER);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isWriteMethod($method) {\n    $method = strtoupper($method);\n    return in_array($method, array(\n      static::METHOD_PUT,\n      static::METHOD_POST,\n      static::METHOD_PATCH,\n      static::METHOD_DELETE,\n    ));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isReadMethod($method) {\n    $method = strtoupper($method);\n    return in_array($method, array(\n      static::METHOD_GET,\n      static::METHOD_HEAD,\n      static::METHOD_OPTIONS,\n      static::METHOD_TRACE,\n      static::METHOD_CONNECT,\n    ));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isValidMethod($method) {\n    $method = strtolower($method);\n    return static::isReadMethod($method) || static::isWriteMethod($method);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isListRequest($resource_path) {\n    if ($this->method != static::METHOD_GET) {\n      return FALSE;\n    }\n    return empty($resource_path) || strpos($resource_path, ',') !== FALSE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getParsedBody() {\n    if ($this->parsedBody) {\n      return $this->parsedBody;\n    }\n    // Find out the body format and parse it into the \\ArrayObject.\n    $this->parsedBody = $this->parseBody($this->method);\n    return $this->parsedBody;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getParsedInput() {\n    if (isset($this->parsedInput)) {\n      return $this->parsedInput;\n    }\n    // Get the input data provided via URL.\n    $this->parsedInput = $this->query;\n    unset($this->parsedInput['q']);\n    return $this->parsedInput;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPagerInput() {\n    $input = $this->getParsedInput();\n    if (!isset($input['page'])) {\n      $page = array('number' => 1);\n    }\n    else {\n      $page = $input['page'];\n      if (!is_array($page)) {\n        $page = array('number' => $page);\n      }\n    }\n    if (isset($input['range'])) {\n      $page['size'] = $input['range'];\n    }\n    return $page + array('number' => 1);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setParsedInput(array $input) {\n    $this->parsedInput = $input;\n  }\n\n  /**\n   * Parses the body.\n   *\n   * @param string $method\n   *   The HTTP method.\n   *\n   * @return array\n   *   The parsed body.\n   */\n  protected function parseBody($method) {\n    if (!static::isWriteMethod($method)) {\n      return NULL;\n    }\n    $content_type = $this\n      ->getHeaders()\n      ->get('Content-Type')\n      ->get();\n\n    $content_type = reset($content_type);\n    $content_type = $content_type ?: 'application/x-www-form-urlencoded';\n    return static::parseBodyContentType($content_type);\n  }\n\n  /**\n   * Parses the provided payload according to a content type.\n   *\n   * @param string $content_type\n   *   The contents of the Content-Type header.\n   *\n   * @return array\n   *   The parsed body.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   */\n  protected static function parseBodyContentType($content_type) {\n    if (!$input_string = file_get_contents('php://input')) {\n      return NULL;\n    }\n    if ($content_type == 'application/x-www-form-urlencoded') {\n      $body = NULL;\n      parse_str($input_string, $body);\n      return $body;\n    }\n    // Use the Content Type header to negotiate a formatter to parse the body.\n    $formatter = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter($content_type);\n    return $formatter->parseBody($input_string);\n  }\n\n  /**\n   * Parses the input data.\n   *\n   * @return array\n   *   The parsed input.\n   */\n  protected static function parseInput() {\n    return $_GET;\n  }\n\n  /**\n   * Helps fixing the fields to ensure that dot-notation makes sense.\n   *\n   * Make sure to add all of the parents for the dot-notation sparse\n   * fieldsets. fields=active,image.category.name,image.description becomes\n   * fields=active,image,image.category,image.category.name,image.description\n   *\n   * @param array $input\n   *   The parsed input to fix.\n   *\n   * @return array\n   *   The parsed input array.\n   */\n  protected function fixQueryFields(array $input) {\n    // Make sure that we include all the parents for full linkage.\n    foreach (array('fields', 'include') as $key_name) {\n      if (empty($input[$key_name])) {\n        continue;\n      }\n      $added_keys = array();\n      foreach (explode(',', $input[$key_name]) as $key) {\n        $parts = explode('.', $key);\n        for ($index = 0; $index < count($parts); $index++) {\n          $path = implode('.', array_slice($parts, 0, $index + 1));\n          $added_keys[$path] = TRUE;\n        }\n      }\n      $input[$key_name] = implode(',', array_keys(array_filter($added_keys))) ?: NULL;\n    }\n\n    return $input;\n  }\n\n  /**\n   * Parses the header names and values from globals.\n   *\n   * @return HttpHeaderBag\n   *   The headers.\n   */\n  protected static function parseHeadersFromGlobals() {\n    $bag = new HttpHeaderBag();\n    $headers = array();\n    if (function_exists('apache_request_headers')) {\n      $headers = apache_request_headers();\n    }\n    else {\n      $content_header_keys = array('CONTENT_TYPE', 'CONTENT_LENGTH');\n      foreach ($_SERVER as $key => $value) {\n        if (strpos($key, 'HTTP_') === 0 || in_array($key, $content_header_keys)) {\n          // Generate the plausible header name based on the $name.\n          // Converts 'HTTP_X_FORWARDED_FOR' to 'X-Forwarded-For'\n          $name = preg_replace('/^HTTP_/', '', $key);\n          $parts = explode('_', $name);\n          $parts = array_map('strtolower', $parts);\n          $parts = array_map('ucfirst', $parts);\n          $name = implode('-', $parts);\n          $headers[$name] = $value;\n        }\n      }\n    }\n    // Iterate over the headers and bag them.\n    foreach ($headers as $name => $value) {\n      $bag->add(HttpHeader::create($name, $value));\n    }\n    return $bag;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPath($strip = TRUE) {\n    // Remove the restful prefix from the beginning of the path.\n    if ($strip && strpos($this->path, variable_get('restful_hook_menu_base_path', 'api')) !== FALSE) {\n      return substr($this->path, strlen(variable_get('restful_hook_menu_base_path', 'api')) + 1);\n    }\n    return $this->path;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function href() {\n    return url($this->path, array(\n      'absolute' => TRUE,\n      'query' => $this->query,\n    ));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getHeaders() {\n    return $this->headers;\n  }\n\n  /**\n   * Get the credentials based on the $_SERVER variables.\n   *\n   * @return array\n   *   A numeric array with the username and password.\n   */\n  protected static function getCredentials() {\n    $username = empty($_SERVER['PHP_AUTH_USER']) ? NULL : $_SERVER['PHP_AUTH_USER'];\n    $password = empty($_SERVER['PHP_AUTH_PW']) ? NULL : $_SERVER['PHP_AUTH_PW'];\n\n    // Try to fill PHP_AUTH_USER & PHP_AUTH_PW with REDIRECT_HTTP_AUTHORIZATION\n    // for compatibility with Apache PHP CGI/FastCGI.\n    // This requires the following line in your \".htaccess\"-File:\n    // RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n    $authorization_header = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : NULL;\n    $authorization_header = $authorization_header ?: (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) ? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] : NULL);\n    if (!empty($authorization_header) && !isset($username) && !isset($password)) {\n      if (!$token = StringHelper::removePrefix('Basic ', $authorization_header)) {\n        return NULL;\n      }\n      $authentication = base64_decode($token);\n      list($username, $password) = explode(':', $authentication);\n      $_SERVER['PHP_AUTH_USER'] = $username;\n      $_SERVER['PHP_AUTH_PW'] = $password;\n    }\n\n    return array($username, $password);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getUser() {\n    list($account,) = static::getCredentials();\n    return $account;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPassword() {\n    list(, $password) = static::getCredentials();\n    return $password;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMethod() {\n    return $this->method;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setMethod($method) {\n    $this->method = strtoupper($method);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getServer() {\n    return $this->server;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setApplicationData($key, $value) {\n    $this->applicationData[$key] = $value;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function clearApplicationData() {\n    $this->applicationData = array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getApplicationData($key) {\n    if (!isset($this->applicationData[$key])) {\n      return NULL;\n    }\n    return $this->applicationData[$key];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isSecure() {\n    if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])->getValueString()) {\n      return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1'));\n    }\n    $https = $this->server['HTTPS'];\n    return !empty($https) && strtolower($https) !== 'off';\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCookies() {\n    return $this->cookies;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFiles() {\n    return $this->files;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCsrfToken() {\n    return $this->csrfToken;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isViaRouter() {\n    return $this->viaRouter;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setViaRouter($via_router) {\n    $this->viaRouter = $via_router;\n  }\n\n}\n"
  },
  {
    "path": "src/Http/RequestInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\RequestInterface.\n */\n\nnamespace Drupal\\restful\\Http;\n\ninterface RequestInterface {\n\n  const HEADER_CLIENT_IP = 'client_ip';\n  const HEADER_CLIENT_HOST = 'client_host';\n  const HEADER_CLIENT_PROTO = 'client_proto';\n  const HEADER_CLIENT_PORT = 'client_port';\n\n  const METHOD_HEAD = 'HEAD';\n  const METHOD_GET = 'GET';\n  const METHOD_POST = 'POST';\n  const METHOD_PUT = 'PUT';\n  const METHOD_PATCH = 'PATCH';\n  const METHOD_DELETE = 'DELETE';\n  const METHOD_PURGE = 'PURGE';\n  const METHOD_OPTIONS = 'OPTIONS';\n  const METHOD_TRACE = 'TRACE';\n  const METHOD_CONNECT = 'CONNECT';\n\n  /**\n   * Creates a new request with values from PHP's super globals.\n   *\n   * @return RequestInterface\n   *   Request A Request instance\n   */\n  public static function createFromGlobals();\n\n  /**\n   * Creates a Request based on a given URI and configuration.\n   *\n   * @param string $path\n   *   The requested path.\n   * @param array $query\n   *   The query string parameters being passed.\n   * @param string $method\n   *   A valid HTTP method\n   * @param HttpHeaderBag $headers\n   *   The headers for the request\n   * @param bool $via_router\n   *   Boolean indicating that if the requested was created via the Drupal's\n   *   menu router.\n   * @param string $csrf_token\n   *   A CSRF token that applies to the current request.\n   * @param array $cookies\n   *   An array of key value pairs containing information about the cookies.\n   * @param array $files\n   *   An array of key value pairs containing information about the files.\n   * @param array $server\n   *   An array of key value pairs containing information about the server.\n   *\n   * @return RequestInterface Request\n   *   A Request instance\n   */\n  public static function create($path, array $query = array(), $method = 'GET', HttpHeaderBag $headers = NULL, $via_router = FALSE, $csrf_token = NULL, array $cookies = array(), array $files = array(), array $server = array());\n\n  /**\n   * Determines if the HTTP method represents a write operation.\n   *\n   * @param string $method\n   *   The method name.\n   *\n   * @return boolean\n   *   TRUE if it is a write operation. FALSE otherwise.\n   */\n  public static function isWriteMethod($method);\n\n  /**\n   * Determines if the HTTP method represents a read operation.\n   *\n   * @param string $method\n   *   The method name.\n   *\n   * @return boolean\n   *   TRUE if it is a read operation. FALSE otherwise.\n   */\n  public static function isReadMethod($method);\n\n  /**\n   * Determines if the HTTP method is one of the known methods.\n   *\n   * @param string $method\n   *   The method name.\n   *\n   * @return boolean\n   *   TRUE if it is a known method. FALSE otherwise.\n   */\n  public static function isValidMethod($method);\n\n  /**\n   * Helper method to know if the current request is for a list.\n   *\n   * @param string $resource_path\n   *   The resource path without any prefixes.\n   *\n   * @return boolean\n   *   TRUE if the request is for a list. FALSE otherwise.\n   */\n  public function isListRequest($resource_path);\n\n  /**\n   * Parses the body string.\n   *\n   * @return array\n   *   The parsed body.\n   */\n  public function getParsedBody();\n\n  /**\n   * Parses the input data provided via URL params.\n   *\n   * @return array\n   *   The parsed input.\n   */\n  public function getParsedInput();\n\n  /**\n   * Parses the input data provided via URL params.\n   *\n   * @param array $input\n   *   The input to set.\n   */\n  public function setParsedInput(array $input);\n\n  /**\n   * Gets the request path.\n   *\n   * @param bool $strip\n   *   If TRUE it will strip the restful API prefix from the beginning.\n   *\n   * @return string\n   *   The path.\n   */\n  public function getPath($strip = TRUE);\n\n  /**\n   * Gets the fully qualified URL with the query params.\n   *\n   * @return string\n   *   The URL.\n   */\n  public function href();\n\n  /**\n   * Gets the headers bag.\n   *\n   * @return HttpHeaderBag\n   */\n  public function getHeaders();\n\n  /**\n   * Returns the user.\n   *\n   * @return\n   *   string|null\n   */\n  public function getUser();\n\n  /**\n   * Returns the password.\n   *\n   * @return\n   *   string|null\n   */\n  public function getPassword();\n\n  /**\n   * Get the HTTP method.\n   *\n   * @return string\n   */\n  public function getMethod();\n\n  /**\n   * Set the HTTP method.\n   *\n   * @param string $method\n   *   The method to set.\n   */\n  public function setMethod($method);\n\n  /**\n   * Get the server information.\n   *\n   * @return array\n   */\n  public function getServer();\n\n  /**\n   * Sets an object in the application data store.\n   *\n   * @param string $key\n   *   Identifier.\n   * @param mixed $value\n   *   The data to store as part of the request.\n   */\n  public function setApplicationData($key, $value);\n\n  /**\n   * Resets the application data.\n   */\n  public function clearApplicationData();\n\n  /**\n   * Gets an object from the application data store.\n   *\n   * @param string $key\n   *   Identifier.\n   *\n   * @return mixed\n   *   The data stored as part of the request.\n   */\n  public function getApplicationData($key);\n\n  /**\n   * Checks whether the request is secure or not.\n   *\n   * This method can read the client port from the \"X-Forwarded-Proto\" header\n   * when trusted proxies were set via \"setTrustedProxies()\".\n   *\n   * The \"X-Forwarded-Proto\" header must contain the protocol: \"https\" or\n   * \"http\".\n   *\n   * If your reverse proxy uses a different header name than \"X-Forwarded-Proto\"\n   * (\"SSL_HTTPS\" for instance), configure it via \"setTrustedHeaderName()\" with\n   * the \"client-proto\" key.\n   *\n   * @return bool\n   */\n  public function isSecure();\n\n  /**\n   * Get the files in the request.\n   *\n   * @return array\n   *   The available files in the request.\n   */\n  public function getFiles();\n\n  /**\n   * Get CSRF Token.\n   *\n   * @return string\n   *   Gets the CSRF token.\n   */\n  public function getCsrfToken();\n\n  /**\n   * Is via router.\n   *\n   * @return bool\n   *   TRUE if the request was generated via the Drupal's menu router.\n   */\n  public function isViaRouter();\n\n  /**\n   * Marks the request as being via Drupal's menu router.\n   *\n   * @param bool $via_router\n   *   The flag to set.\n   */\n  public function setViaRouter($via_router);\n\n  /**\n   * @return array\n   */\n  public function getCookies();\n\n  /**\n   * Get the normalized pager input.\n   *\n   * This is to support page=1&range=6 and page[number]=1&page[size]=6 at the\n   * same time.\n   *\n   * @return array\n   *   An associative array with the pager information in the form of\n   *   page[number]=1&page[size]=6.\n   */\n  public function getPagerInput();\n\n}\n"
  },
  {
    "path": "src/Http/Response.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\Response.\n *\n * A lot of this has been extracted from the Symfony Response class.\n */\n\nnamespace Drupal\\restful\\Http;\n\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\n\nclass Response implements ResponseInterface {\n\n  /**\n   * @var HttpHeaderBag\n   */\n  public $headers;\n\n  /**\n   * @var string\n   */\n  protected $content;\n\n  /**\n   * @var string\n   */\n  protected $version;\n\n  /**\n   * @var int\n   */\n  protected $statusCode;\n\n  /**\n   * @var string\n   */\n  protected $statusText;\n\n  /**\n   * @var string\n   */\n  protected $charset;\n\n  /**\n   * Status codes translation table.\n   *\n   * The list of codes is complete according to the\n   * {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry}\n   * (last updated 2012-02-13).\n   *\n   * Unless otherwise noted, the status code is defined in RFC2616.\n   *\n   * @var array\n   */\n  public static $statusTexts = array(\n    100 => 'Continue',\n    101 => 'Switching Protocols',\n    102 => 'Processing',            // RFC2518\n    200 => 'OK',\n    201 => 'Created',\n    202 => 'Accepted',\n    203 => 'Non-Authoritative Information',\n    204 => 'No Content',\n    205 => 'Reset Content',\n    206 => 'Partial Content',\n    207 => 'Multi-Status',          // RFC4918\n    208 => 'Already Reported',      // RFC5842\n    226 => 'IM Used',               // RFC3229\n    300 => 'Multiple Choices',\n    301 => 'Moved Permanently',\n    302 => 'Found',\n    303 => 'See Other',\n    304 => 'Not Modified',\n    305 => 'Use Proxy',\n    306 => 'Reserved',\n    307 => 'Temporary Redirect',\n    308 => 'Permanent Redirect',    // RFC7238\n    400 => 'Bad Request',\n    401 => 'Unauthorized',\n    402 => 'Payment Required',\n    403 => 'Forbidden',\n    404 => 'Not Found',\n    405 => 'Method Not Allowed',\n    406 => 'Not Acceptable',\n    407 => 'Proxy Authentication Required',\n    408 => 'Request Timeout',\n    409 => 'Conflict',\n    410 => 'Gone',\n    411 => 'Length Required',\n    412 => 'Precondition Failed',\n    413 => 'Request Entity Too Large',\n    414 => 'Request-URI Too Long',\n    415 => 'Unsupported Media Type',\n    416 => 'Requested Range Not Satisfiable',\n    417 => 'Expectation Failed',\n    418 => 'I\\'m a teapot',                                               // RFC2324\n    422 => 'Unprocessable Entity',                                        // RFC4918\n    423 => 'Locked',                                                      // RFC4918\n    424 => 'Failed Dependency',                                           // RFC4918\n    425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817\n    426 => 'Upgrade Required',                                            // RFC2817\n    428 => 'Precondition Required',                                       // RFC6585\n    429 => 'Too Many Requests',                                           // RFC6585\n    431 => 'Request Header Fields Too Large',                             // RFC6585\n    500 => 'Internal Server Error',\n    501 => 'Not Implemented',\n    502 => 'Bad Gateway',\n    503 => 'Service Unavailable',\n    504 => 'Gateway Timeout',\n    505 => 'HTTP Version Not Supported',\n    506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295\n    507 => 'Insufficient Storage',                                        // RFC4918\n    508 => 'Loop Detected',                                               // RFC5842\n    510 => 'Not Extended',                                                // RFC2774\n    511 => 'Network Authentication Required',                             // RFC6585\n  );\n\n  /**\n   * Constructor.\n   *\n   * @param mixed $content\n   *   The response content, see setContent()\n   * @param int $status\n   *   The response status code\n   * @param array $headers\n   *   An array of response headers\n   *\n   * @throws UnprocessableEntityException\n   *   When the HTTP status code is not valid\n   */\n  public function __construct($content = '', $status = 200, $headers = array()) {\n    $this->headers = new HttpHeaderBag($headers);\n    $this->setContent($content);\n    $this->setStatusCode($status);\n    $this->setProtocolVersion('1.0');\n    if (!$this->headers->has('Date')) {\n      $this->setDate(new \\DateTime(NULL, new \\DateTimeZone('UTC')));\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create($content = '', $status = 200, $headers = array()) {\n    return new static($content, $status, $headers);\n  }\n\n  /**\n   * Returns the Response as an HTTP string.\n   *\n   * The string representation of the Response is the same as the\n   * one that will be sent to the client only if the prepare() method\n   * has been called before.\n   *\n   * @return string\n   *   The Response as an HTTP string\n   *\n   * @see prepare()\n   */\n  public function __toString() {\n    return\n      sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText) . \"\\r\\n\" .\n      $this->headers . \"\\r\\n\" .\n      $this->getContent();\n  }\n\n  /**\n   * Is the response empty?\n   *\n   * @return bool\n   */\n  protected function isEmpty() {\n    return in_array($this->statusCode, array(204, 304));\n  }\n\n  /**\n   * Is response informative?\n   *\n   * @return bool\n   */\n  protected function isInformational() {\n    return $this->statusCode >= 100 && $this->statusCode < 200;\n  }\n\n  /**\n   * Is response successful?\n   *\n   * @return bool\n   */\n  protected function isSuccessful() {\n    return $this->statusCode >= 200 && $this->statusCode < 300;\n  }\n\n  /**\n   * Is response invalid?\n   *\n   * @return bool\n   */\n  protected function isInvalid() {\n    return $this->statusCode < 100 || $this->statusCode >= 600;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare(RequestInterface $request) {\n    $headers = $this->headers;\n    if ($this->isInformational() || $this->isEmpty()) {\n      $this->setContent(NULL);\n      $headers->remove('Content-Type');\n      $headers->remove('Content-Length');\n    }\n    else {\n      // Content-type based on the Request. The content type should have been\n      // set in the RestfulFormatter.\n\n      // Fix Content-Type\n      $charset = $this->charset ?: 'UTF-8';\n      $content_type = $headers->get('Content-Type')->getValueString();\n      if (stripos($content_type, 'text/') === 0 && stripos($content_type, 'charset') === FALSE) {\n        // add the charset\n        $headers->add(HttpHeader::create('Content-Type', $content_type . '; charset=' . $charset));\n      }\n      // Fix Content-Length\n      if ($headers->has('Transfer-Encoding')) {\n        $headers->remove('Content-Length');\n      }\n      if ($request->getMethod() == RequestInterface::METHOD_HEAD) {\n        // cf. RFC2616 14.13\n        $length = $headers->get('Content-Length')->getValueString();\n        $this->setContent(NULL);\n        if ($length) {\n          $headers->add(HttpHeader::create('Content-Length', $length));\n        }\n      }\n    }\n    // Fix protocol\n    $server_info = $request->getServer();\n    if ($server_info['SERVER_PROTOCOL'] != 'HTTP/1.0') {\n      $this->setProtocolVersion('1.1');\n    }\n    // Check if we need to send extra expire info headers\n    if ($this->getProtocolVersion() == '1.0' && $this->headers->get('Cache-Control')->getValueString() == 'no-cache') {\n      $this->headers->add(HttpHeader::create('pragma', 'no-cache'));\n      $this->headers->add(HttpHeader::create('expires', -1));\n    }\n    $this->ensureIEOverSSLCompatibility($request);\n  }\n\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setContent($content) {\n    if ($content !== NULL && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) {\n      throw new InternalServerErrorException(sprintf('The Response content must be a string or object implementing __toString(), \"%s\" given.', gettype($content)));\n    }\n    $this->content = (string) $content;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getContent() {\n    return $this->content;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProtocolVersion($version) {\n    $this->version = $version;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProtocolVersion() {\n    return $this->version;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function send() {\n    $this->sendHeaders();\n    $this->sendContent();\n\n    static::pageFooter();\n  }\n\n  /**\n   * Sends HTTP headers.\n   */\n  protected function sendHeaders() {\n    foreach ($this->headers as $key => $header) {\n      /* @var HttpHeader $header */\n      drupal_add_http_header($header->getName(), $header->getValueString());\n    }\n    drupal_add_http_header('Status', $this->getStatusCode());\n  }\n\n  /**\n   * Sends content for the current web response.\n   */\n  protected function sendContent() {\n    echo $this->content;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setStatusCode($code, $text = NULL) {\n    $this->statusCode = $code = (int) $code;\n    if ($this->isInvalid()) {\n      throw new UnprocessableEntityException(sprintf('The HTTP status code \"%s\" is not valid.', $code));\n    }\n    if ($text === NULL) {\n      $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : '';\n      return;\n    }\n    if ($text === FALSE) {\n      $this->statusText = '';\n      return;\n    }\n    $this->statusText = $text;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getStatusCode() {\n    return $this->statusCode;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCharset($charset) {\n    $this->charset = $charset;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCharset() {\n    return $this->charset;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getHeaders() {\n    return $this->headers;\n  }\n\n  /**\n   * Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9.\n   *\n   * @link http://support.microsoft.com/kb/323308\n   */\n  protected function ensureIEOverSSLCompatibility(Request $request) {\n    $server_info = $request->getServer();\n    if (stripos($this->headers->get('Content-Disposition')->getValueString(), 'attachment') !== FALSE && preg_match('/MSIE (.*?);/i', $server_info['HTTP_USER_AGENT'], $match) == 1 && $request->isSecure() === TRUE) {\n      if (intval(preg_replace(\"/(MSIE )(.*?);/\", \"$2\", $match[0])) < 9) {\n        $this->headers->remove('Cache-Control');\n      }\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setDate(\\DateTime $date) {\n    $date->setTimezone(new \\DateTimeZone('UTC'));\n    $this->headers->add(HttpHeader::create('Date', $date->format('D, d M Y H:i:s') . ' GMT'));\n  }\n\n  /**\n   * Performs end-of-request tasks.\n   *\n   * This function sets the page cache if appropriate, and allows modules to\n   * react to the closing of the page by calling hook_exit().\n   *\n   * This is just a wrapper around drupal_page_footer() so extending classes can\n   * override this method if necessary.\n   *\n   * @see drupal_page_footer().\n   */\n  protected static function pageFooter() {\n    drupal_page_footer();\n  }\n\n}\n"
  },
  {
    "path": "src/Http/ResponseInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Http\\ResponseInterface.\n */\n\nnamespace Drupal\\restful\\Http;\n\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\n\ninterface ResponseInterface {\n\n  /**\n   * Factory.\n   *\n   * @param mixed $content\n   *   The response content, see setContent()\n   * @param int $status\n   *   The response status code\n   * @param array $headers\n   *   An array of response headers\n   *\n   * @return ResponseInterface\n   *   The created object.\n   *\n   * @throws UnprocessableEntityException\n   *   When the HTTP status code is not valid\n   */\n  public static function create($content = '', $status = 200, $headers = array());\n\n  /**\n   * Prepares the Response before it is sent to the client.\n   *\n   * This method tweaks the Response to ensure that it is\n   * compliant with RFC 2616. Most of the changes are based on\n   * the Request that is \"associated\" with this Response.\n   *\n   * @param RequestInterface $request\n   *   A Request instance\n   */\n  public function prepare(RequestInterface $request);\n\n  /**\n   * Sets the response content.\n   *\n   * Valid types are strings, numbers, NULL, and objects that implement a __toString() method.\n   *\n   * @param mixed $content Content that can be cast to string\n   *\n   * @throws InternalServerErrorException\n   */\n  public function setContent($content);\n\n  /**\n   * Gets the current response content.\n   *\n   * @return string Content\n   */\n  public function getContent();\n\n  /**\n   * Sets the HTTP protocol version (1.0 or 1.1).\n   *\n   * @param string $version The HTTP protocol version\n   */\n  public function setProtocolVersion($version);\n\n  /**\n   * Gets the HTTP protocol version.\n   *\n   * @return string The HTTP protocol version\n   */\n  public function getProtocolVersion();\n\n  /**\n   * Sends HTTP headers and content.\n   */\n  public function send();\n\n  /**\n   * Sets the response status code.\n   *\n   * @param int $code\n   *   HTTP status code\n   * @param mixed $text\n   *   HTTP status text\n   *\n   * If the status text is NULL it will be automatically populated for the known\n   * status codes and left empty otherwise.\n   *\n   * @throws UnprocessableEntityException When the HTTP status code is not valid\n   */\n  public function setStatusCode($code, $text = NULL);\n\n  /**\n   * Retrieves the status code for the current web response.\n   *\n   * @return int Status code\n   */\n  public function getStatusCode();\n\n  /**\n   * Sets the response charset.\n   *\n   * @param string $charset Character set\n   */\n  public function setCharset($charset);\n\n  /**\n   * Retrieves the response charset.\n   *\n   * @return string Character set\n   */\n  public function getCharset();\n\n  /**\n   * Get the headers bag.\n   *\n   * @return HttpHeaderBag\n   */\n  public function getHeaders();\n\n  /**\n   * Sets the Date header.\n   *\n   * @param \\DateTime $date\n   *   A \\DateTime instance\n   */\n  public function setDate(\\DateTime $date);\n\n}\n"
  },
  {
    "path": "src/Plugin/AuthenticationPluginManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\AuthenticationPluginManager.\n */\n\nnamespace Drupal\\restful\\Plugin;\n\nuse Drupal\\Core\\Plugin\\DefaultPluginManager;\nuse Drupal\\Core\\Plugin\\Factory\\ContainerFactory;\nuse Drupal\\Core\\Plugin\\Discovery\\YamlDiscovery;\nuse Drupal\\plug\\Util\\Module;\n\n/**\n * Authentication plugin manager.\n */\nclass AuthenticationPluginManager extends DefaultPluginManager {\n\n  use SemiSingletonTrait;\n\n  /**\n   * {@inheritdoc}\n   */\n  protected $defaults = array(\n    // Human readable label for the authentication.\n    'label' => '',\n    // A description of the plugin.\n    'description' => '',\n    'settings' => array(),\n    'id' => '',\n  );\n\n  /**\n   * Constructs AuthenticationPluginManager.\n   *\n   * @param \\Traversable $namespaces\n   *   An object that implements \\Traversable which contains the root paths\n   *   keyed by the corresponding namespace to look for plugin implementations.\n   * @param \\DrupalCacheInterface $cache_backend\n   *   Cache backend instance to use.\n   */\n  public function __construct(\\Traversable $namespaces, \\DrupalCacheInterface $cache_backend) {\n    parent::__construct('Plugin/authentication', $namespaces, 'Drupal\\restful\\Plugin\\authentication\\AuthenticationInterface', '\\Drupal\\restful\\Annotation\\Authentication');\n    $this->setCacheBackend($cache_backend, 'authentication_plugins');\n    $this->alterInfo('authentication_plugin');\n  }\n\n  /**\n   * AuthenticationPluginManager factory method.\n   *\n   * @param string $bin\n   *   The cache bin for the plugin manager.\n   * @param bool $avoid_singleton\n   *   Do not use the stored singleton.\n   *\n   * @return AuthenticationPluginManager\n   *   The created manager.\n   */\n  public static function create($bin = 'cache', $avoid_singleton = FALSE) {\n    $factory = function ($bin) {\n      return new static(Module::getNamespaces(), _cache_get_object($bin));\n    };\n    if ($avoid_singleton) {\n      $factory($bin);\n    }\n    return static::semiSingletonInstance($factory, array($bin));\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/ConfigurablePluginTrait.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\ConfigurablePluginTrait\n */\n\nnamespace Drupal\\restful\\Plugin;\n\ntrait ConfigurablePluginTrait {\n\n  /**\n   * Plugin instance configuration.\n   *\n   * @var array\n   */\n  protected $instanceConfiguration;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getConfiguration() {\n    if (!isset($this->instanceConfiguration)) {\n      $this->instanceConfiguration = $this->defaultConfiguration();\n    }\n    return $this->instanceConfiguration;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setConfiguration(array $configuration) {\n    $this->instanceConfiguration = $configuration;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function defaultConfiguration() {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function calculateDependencies() {\n    return array();\n  }\n\n\n\n}\n"
  },
  {
    "path": "src/Plugin/FormatterPluginManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\FormatterPluginManager.\n */\n\nnamespace Drupal\\restful\\Plugin;\n\nuse Drupal\\Core\\Plugin\\DefaultPluginManager;\nuse Drupal\\plug\\Util\\Module;\n\nclass FormatterPluginManager extends DefaultPluginManager {\n\n  /**\n   * Constructs FormatterPluginManager.\n   *\n   * @param \\Traversable $namespaces\n   *   An object that implements \\Traversable which contains the root paths\n   *   keyed by the corresponding namespace to look for plugin implementations.\n   * @param \\DrupalCacheInterface $cache_backend\n   *   Cache backend instance to use.\n   */\n  public function __construct(\\Traversable $namespaces, \\DrupalCacheInterface $cache_backend) {\n    parent::__construct('Plugin/formatter', $namespaces, 'Drupal\\restful\\Plugin\\formatter\\FormatterInterface', '\\Drupal\\restful\\Annotation\\Formatter');\n    $this->setCacheBackend($cache_backend, 'formatter_plugins');\n    $this->alterInfo('formatter_plugin');\n  }\n\n  /**\n   * FormatterPluginManager factory method.\n   *\n   * @param string $bin\n   *   The cache bin for the plugin manager.\n   *\n   * @return FormatterPluginManager\n   *   The created manager.\n   */\n  public static function create($bin = 'cache') {\n    return new static(Module::getNamespaces(), _cache_get_object($bin));\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/RateLimitPluginManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\RateLimitPluginManager.\n */\n\nnamespace Drupal\\restful\\Plugin;\n\nuse Drupal\\Core\\Plugin\\DefaultPluginManager;\nuse Drupal\\plug\\Util\\Module;\n\nclass RateLimitPluginManager extends DefaultPluginManager {\n\n  /**\n   * Constructs RateLimitPluginManager.\n   *\n   * @param \\Traversable $namespaces\n   *   An object that implements \\Traversable which contains the root paths\n   *   keyed by the corresponding namespace to look for plugin implementations.\n   * @param \\DrupalCacheInterface $cache_backend\n   *   Cache backend instance to use.\n   */\n  public function __construct(\\Traversable $namespaces, \\DrupalCacheInterface $cache_backend) {\n    parent::__construct('Plugin/rate_limit', $namespaces, 'Drupal\\restful\\Plugin\\rate_limit\\RateLimitInterface', '\\Drupal\\restful\\Annotation\\RateLimit');\n    $this->setCacheBackend($cache_backend, 'rate_limit_plugins');\n    $this->alterInfo('rate_limit_plugin');\n  }\n\n  /**\n   * RateLimitPluginManager factory method.\n   *\n   * @param string $bin\n   *   The cache bin for the plugin manager.\n   *\n   * @return RateLimitPluginManager\n   *   The created manager.\n   */\n  public static function create($bin = 'cache') {\n    return new static(Module::getNamespaces(), _cache_get_object($bin));\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/ResourcePluginManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\ResourcePluginManager.\n */\n\nnamespace Drupal\\restful\\Plugin;\n\nuse Drupal\\Core\\Plugin\\DefaultPluginManager;\nuse Drupal\\plug\\Util\\Module;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\nclass ResourcePluginManager extends DefaultPluginManager {\n\n  /**\n   * Request object.\n   *\n   * @var RequestInterface\n   */\n  protected $request;\n\n  /**\n   * Constructs ResourcePluginManager.\n   *\n   * @param \\Traversable $namespaces\n   *   An object that implements \\Traversable which contains the root paths\n   *   keyed by the corresponding namespace to look for plugin implementations.\n   * @param \\DrupalCacheInterface $cache_backend\n   *   Cache backend instance to use.\n   * @param RequestInterface $request\n   *   The request object.\n   */\n  public function __construct(\\Traversable $namespaces, \\DrupalCacheInterface $cache_backend, RequestInterface $request) {\n    parent::__construct('Plugin/resource', $namespaces, 'Drupal\\restful\\Plugin\\resource\\ResourceInterface', '\\Drupal\\restful\\Annotation\\Resource');\n    $this->setCacheBackend($cache_backend, 'resource_plugins');\n    $this->alterInfo('resource_plugin');\n    $this->request = $request;\n  }\n\n  /**\n   * ResourcePluginManager factory method.\n   *\n   * @param string $bin\n   *   The cache bin for the plugin manager.\n   * @param RequestInterface $request\n   *   The request object.\n   *\n   * @return ResourcePluginManager\n   *   The created manager.\n   */\n  public static function create($bin = 'cache', RequestInterface $request = NULL) {\n    return new static(Module::getNamespaces(), _cache_get_object($bin), $request);\n  }\n\n  /**\n   * Overrides PluginManagerBase::createInstance().\n   *\n   * This method is overridden to set the request object when the resource\n   * object is instantiated.\n   */\n  public function createInstance($plugin_id, array $configuration = array()) {\n    /* @var ResourceInterface $resource */\n    $resource = parent::createInstance($plugin_id, $configuration);\n    $resource->setRequest($this->request);\n    return $resource;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/SemiSingletonTrait.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\SemiSingletonTrait.\n */\n\nnamespace Drupal\\restful\\Plugin;\n\n/**\n * Class SemiSingletonTrait.\n *\n * @package Drupal\\restful\\Plugin\n */\ntrait SemiSingletonTrait {\n\n  /**\n   * The already created manager.\n   *\n   * @var mixed\n   */\n  protected static $singleton;\n\n  /**\n   * Gets the singleton based on the factory callable.\n   *\n   * @param callable $factory\n   *   The factory that creates the actual object.\n   * @param array $params\n   *   The parameters to be passed to the factory.\n   *\n   * @return mixed\n   *   The singleton object.\n   */\n  protected static function semiSingletonInstance(callable $factory, array $params = array()) {\n    if (!static::$singleton) {\n      static::$singleton = call_user_func_array($factory, $params);\n    }\n    return static::$singleton;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/authentication/Authentication.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\authentication\\Authentication\n */\n\nnamespace Drupal\\restful\\Plugin\\authentication;\n\nuse Drupal\\Component\\Plugin\\ConfigurablePluginInterface;\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\ConfigurablePluginTrait;\n\nabstract class Authentication extends PluginBase implements ConfigurablePluginInterface, AuthenticationInterface {\n\n  use ConfigurablePluginTrait;\n\n  /**\n   * Token value for token generation functions.\n   */\n  const TOKEN_VALUE = 'rest';\n\n  /**\n   * Settings from the plugin definition.\n   *\n   * @var array\n   */\n  protected $settings;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function applies(RequestInterface $request) {\n    // By default assume that the request can be checked for authentication.\n    return TRUE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getName() {\n    return $this->getPluginId();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/authentication/AuthenticationInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\authentication\\Authentication\n */\n\nnamespace Drupal\\restful\\Plugin\\authentication;\n\nuse Drupal\\Component\\Plugin\\PluginInspectionInterface;\nuse Drupal\\restful\\Http\\RequestInterface;\n\ninterface AuthenticationInterface extends PluginInspectionInterface {\n\n  /**\n   * Authenticate the request by trying to match a user.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   *\n   * @return object\n   *   The user object.\n   */\n  public function authenticate(RequestInterface $request);\n\n  /**\n   * Determines if the request can be checked for authentication. For example,\n   * when authenticating with HTTP header, return FALSE if the header values do\n   * not exist.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   *\n   * @return bool\n   *   TRUE if the request can be checked for authentication, FALSE otherwise.\n   */\n  public function applies(RequestInterface $request);\n\n  /**\n   * Get the name of the authentication plugin.\n   *\n   * @return string\n   *   The name.\n   */\n  public function getName();\n\n}\n"
  },
  {
    "path": "src/Plugin/authentication/BasicAuthentication.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\authentication\\BasicAuthentication\n */\n\nnamespace Drupal\\restful\\Plugin\\authentication;\n\nuse Drupal\\restful\\Exception\\FloodException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\n/**\n * Class BasicAuthentication\n * @package Drupal\\restful\\Plugin\\authentication\n *\n * @Authentication(\n *   id = \"basic_auth\",\n *   label = \"Basic authentication\",\n *   description = \"Authenticate requests based on basic auth.\",\n * )\n */\nclass BasicAuthentication extends Authentication {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function applies(RequestInterface $request) {\n    if (variable_get('restful_skip_basic_auth', FALSE)) {\n      // Skip basic auth. The variable may be set if .htaccess password is set\n      // on the server.\n      return NULL;\n    }\n    $username = $request->getUser();\n    $password = $request->getPassword();\n\n    return isset($username) && isset($password);\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * @see user_login_authenticate_validate().\n   */\n  public function authenticate(RequestInterface $request) {\n    $username = $request->getUser();\n    $password = $request->getPassword();\n\n    // Do not allow any login from the current user's IP if the limit has been\n    // reached. Default is 50 failed attempts allowed in one hour. This is\n    // independent of the per-user limit to catch attempts from one IP to log\n    // in to many different user accounts.  We have a reasonably high limit\n    // since there may be only one apparent IP for all users at an institution.\n    if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) {\n      throw new FloodException(format_string('Rejected by ip flood control.'));\n    }\n    if (!$uid = db_query_range(\"SELECT uid FROM {users} WHERE name = :name AND status = 1\", 0, 1, array(':name' => $username))->fetchField()) {\n      // Always register an IP-based failed login event.\n      flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600), ip_address());\n      return NULL;\n    }\n    if (variable_get('user_failed_login_identifier_uid_only', FALSE)) {\n      // Register flood events based on the uid only, so they apply for any\n      // IP address. This is the most secure option.\n      $identifier = $uid;\n    }\n    else {\n      // The default identifier is a combination of uid and IP address. This\n      // is less secure but more resistant to denial-of-service attacks that\n      // could lock out all users with public user names.\n      $identifier = $uid . '-' . ip_address();\n    }\n\n    // Don't allow login if the limit for this user has been reached.\n    // Default is to allow 5 failed attempts every 6 hours.\n    if (flood_is_allowed('failed_login_attempt_user', variable_get('user_failed_login_user_limit', 5), variable_get('user_failed_login_user_window', 21600), $identifier)) {\n      // We are not limited by flood control, so try to authenticate.\n      if ($uid = user_authenticate($username, $password)) {\n        // Clear the user based flood control.\n        flood_clear_event('failed_login_attempt_user', $identifier);\n        return user_load($uid);\n      }\n      flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 3600), $identifier);\n    }\n    else {\n      flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 3600), $identifier);\n      throw new FloodException(format_string('Rejected by user flood control.'));\n    }\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/authentication/CookieAuthentication.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\authentication\\CookieAuthentication\n */\n\nnamespace Drupal\\restful\\Plugin\\authentication;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\ForbiddenException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\RestfulManager;\n\n/**\n * Class CookieAuthentication\n * @package Drupal\\restful\\Plugin\\authentication\n *\n * @Authentication(\n *   id = \"cookie\",\n *   label = \"Cookie based authentication\",\n *   description = \"Authenticate requests based on the user cookie.\",\n * )\n */\nclass CookieAuthentication extends Authentication {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function authenticate(RequestInterface $request) {\n    if (!drupal_session_started() && !$this->isCli($request)) {\n      return NULL;\n    }\n\n    global $user;\n    $account = user_load($user->uid);\n\n    if (!$request::isWriteMethod($request->getMethod()) || $request->getApplicationData('rest_call')) {\n      // Request is done via API not CURL, or not a write operation, so we don't\n      // need to check for a CSRF token.\n      return $account;\n    }\n\n    if (!RestfulManager::isRestfulPath($request)) {\n      return $account;\n    }\n    if (!$request->getCsrfToken()) {\n      throw new BadRequestException('No CSRF token passed in the HTTP header.');\n    }\n    if (!drupal_valid_token($request->getCsrfToken(), Authentication::TOKEN_VALUE)) {\n      throw new ForbiddenException('CSRF token validation failed.');\n    }\n\n    // CSRF validation passed.\n    return $account;\n  }\n\n  /**\n   * Detects whether the script is running from a command line environment.\n   *\n   * @param RequestInterface $request.\n   *   The request.\n   *\n   * @return bool\n   *   TRUE if a command line environment is detected. FALSE otherwise.\n   */\n  protected function isCli(RequestInterface $request) {\n    // Needed to detect if run-tests.sh is running the tests.\n    $cli = $request->getHeaders()->get('User-Agent')->getValueString() == 'Drupal command line';\n    return $cli || drupal_is_cli();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/authentication/OAuth2ServerAuthentication.php",
    "content": "<?php\n\nnamespace Drupal\\restful\\Plugin\\authentication;\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\UnauthorizedException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\ResourcePluginManager;\n\n/**\n * Authentication support for oauth2_server.\n *\n * @Authentication(\n *   id = \"oauth2\",\n *   label = \"OAuth2 authentication\",\n *   description = \"Authenticate requests based on oauth2_server auth.\",\n * )\n */\nclass OAuth2ServerAuthentication extends Authentication {\n\n  /**\n   * The resource manager.\n   *\n   * @var \\Drupal\\restful\\Resource\\ResourceManagerInterface\n   */\n  protected $resourceManager;\n\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n    $this->resourceManager = restful()->getResourceManager();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function applies(RequestInterface $request) {\n    return module_exists('oauth2_server') && $this->getOAuth2Info($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function authenticate(RequestInterface $request) {\n    $oauth2_info = $this->getOAuth2Info($request);\n    if (!$oauth2_info) {\n      throw new ServerConfigurationException('The resource uses OAuth2 authentication but does not specify the OAuth2 server.');\n    }\n\n    $result = oauth2_server_check_access($oauth2_info['server'], $oauth2_info['scope']);\n    if ($result instanceof \\OAuth2\\Response) {\n      throw new UnauthorizedException($result->getResponseBody(), $result->getStatusCode());\n    }\n    elseif (empty($result['user_id'])) {\n      return NULL;\n    }\n    return user_load($result['user_id']);\n  }\n\n  /**\n   * Get OAuth2 information from the request.\n   *\n   * @param \\Drupal\\restful\\Http\\RequestInterface $request\n   *   The request.\n   *\n   * @return array|null\n   *   Simple associative array with the following keys:\n   *   - server: The OAuth2 server to authenticate against.\n   *   - scope: The scope required for the resource.\n   */\n  protected function getOAuth2Info(RequestInterface $request) {\n    $plugin_id = $this->getResourcePluginIdFromRequest();\n    if (!$plugin_id) {\n      // If the plugin can't be determined, it is probably not a request to the\n      // resource but something else that is just loading all the plugins.\n      return NULL;\n    }\n\n    $plugin_definition = ResourcePluginManager::create('cache', $request)->getDefinition($plugin_id);\n\n    if (empty($plugin_definition['oauth2Server'])) {\n      return NULL;\n    }\n\n    $server = $plugin_definition['oauth2Server'];\n    $scope = !empty($plugin_definition['oauth2Scope']) ? $plugin_definition['oauth2Scope'] : '';\n    return ['server' => $server, 'scope' => $scope];\n  }\n\n  /**\n   * Get the resource plugin id requested.\n   *\n   * @return null|string\n   *   The plugin id of the resource that was requested.\n   */\n  protected function getResourcePluginIdFromRequest() {\n    $resource_name = $this->resourceManager->getResourceIdFromRequest();\n    $version = $this->resourceManager->getVersionFromRequest();\n\n    if (!$resource_name || !$version) {\n      return NULL;\n    }\n\n    return $resource_name . PluginBase::DERIVATIVE_SEPARATOR . $version[0] . '.' . $version[1];\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/formatter/Formatter.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\Formatter\n */\n\nnamespace Drupal\\restful\\Plugin\\formatter;\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Plugin\\ConfigurablePluginTrait;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\RenderCache\\Entity\\CacheFragment;\nuse Drupal\\restful\\RenderCache\\RenderCache;\n\n/**\n * Class Formatter.\n *\n * @package Drupal\\restful\\Plugin\\formatter\n */\nabstract class Formatter extends PluginBase implements FormatterInterface {\n\n  use ConfigurablePluginTrait;\n\n  /**\n   * The resource handler containing more info about the request.\n   *\n   * @var ResourceInterface\n   */\n  protected $resource;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function format(array $data) {\n    return $this->render($this->prepare($data));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getContentTypeHeader() {\n    // Default to the most generic content type.\n    return 'application/hal+json; charset=utf-8';\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResource() {\n    if (isset($this->resource)) {\n      return $this->resource;\n    }\n\n    // Get the resource from the instance configuration.\n    $instance_configuration = $this->getConfiguration();\n    if (empty($instance_configuration['resource'])) {\n      return NULL;\n    }\n    $this->resource = $instance_configuration['resource'] instanceof ResourceInterface ? $instance_configuration['resource'] : NULL;\n    return $this->resource;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResource(ResourceInterface $resource) {\n    $this->resource = $resource;\n    $this->setConfiguration(array(\n      'resource' => $resource,\n    ));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function parseBody($body) {\n    throw new ServerConfigurationException(sprintf('Invalid body parser for: %s.', $body));\n  }\n\n  /**\n   * Helper function to know if a variable is iterable or not.\n   *\n   * @param mixed $input\n   *   The variable to test.\n   *\n   * @return bool\n   *   TRUE if the variable is iterable.\n   */\n  protected static function isIterable($input) {\n    return is_array($input) || $input instanceof \\Traversable || $input instanceof \\stdClass;\n  }\n\n  /**\n   * Checks if the passed in data to be rendered can be cached.\n   *\n   * @param mixed $data\n   *   The data to be prepared and rendered.\n   *\n   * @return bool\n   *   TRUE if the data can be cached.\n   */\n  protected function isCacheEnabled($data) {\n    // We are only caching field collections, but you could cache at different\n    // layers too.\n    if (!$data instanceof ResourceFieldCollectionInterface) {\n      return FALSE;\n    }\n    if (!$context = $data->getContext()) {\n      return FALSE;\n    }\n    return !empty($context['cache_fragments']);\n  }\n\n  /**\n   * Gets the cached computed value for the fields to be rendered.\n   *\n   * @param mixed $data\n   *   The data to be rendered.\n   *\n   * @return mixed\n   *   The cached data.\n   */\n  protected function getCachedData($data) {\n    if (!$render_cache = $this->createCacheController($data)) {\n      return NULL;\n    }\n    return $render_cache->get();\n  }\n\n  /**\n   * Gets the cached computed value for the fields to be rendered.\n   *\n   * @param mixed $data\n   *   The data to be rendered.\n   *\n   * @return string\n   *   The cache hash.\n   */\n  protected function getCacheHash($data) {\n    if (!$render_cache = $this->createCacheController($data)) {\n      return NULL;\n    }\n    return $render_cache->getCid();\n  }\n\n  /**\n   * Gets the cached computed value for the fields to be rendered.\n   *\n   * @param mixed $data\n   *   The data to be rendered.\n   * @param mixed $output\n   *   The rendered data to output.\n   * @param string[] $parent_hashes\n   *   An array that holds the name of the parent cache hashes that lead to the\n   *   current data structure.\n   */\n  protected function setCachedData($data, $output, array $parent_hashes = array()) {\n    if (!$render_cache = $this->createCacheController($data)) {\n      return;\n    }\n    $render_cache->set($output);\n    // After setting the cache for the current object, mark all parent hashes\n    // with the current cache fragments. That will have the effect of allowing\n    // to clear the parent caches based on the children fragments.\n    $fragments = $this->cacheFragments($data);\n    foreach ($parent_hashes as $parent_hash) {\n      foreach ($fragments as $tag_type => $tag_value) {\n        // Check if the fragment already exists.\n        $query = new \\EntityFieldQuery();\n        $duplicate = (bool) $query\n          ->entityCondition('entity_type', 'cache_fragment')\n          ->propertyCondition('value', $tag_value)\n          ->propertyCondition('type', $tag_type)\n          ->propertyCondition('hash', $parent_hash)\n          ->count()\n          ->execute();\n        if ($duplicate) {\n          continue;\n        }\n        $cache_fragment = new CacheFragment(array(\n          'value' => $tag_value,\n          'type' => $tag_type,\n          'hash' => $parent_hash,\n        ), 'cache_fragment');\n        try {\n          $cache_fragment->save();\n        }\n        catch (\\Exception $e) {\n          watchdog_exception('restful', $e);\n        }\n      }\n    }\n  }\n\n  /**\n   * Gets a cache controller based on the data to be rendered.\n   *\n   * @param mixed $data\n   *   The data to be rendered.\n   *\n   * @return \\Drupal\\restful\\RenderCache\\RenderCacheInterface;\n\n   *   The cache controller.\n   */\n  protected function createCacheController($data) {\n    if (!$cache_fragments = $this->cacheFragments($data)) {\n      return NULL;\n    }\n    // Add the formatter fragment because every formatter may prepare the data\n    // differently.\n    /* @var \\Doctrine\\Common\\Collections\\ArrayCollection $cache_fragments */\n    $cache_fragments->set('formatter', $this->getPluginId());\n    /* @var \\Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource $cached_resource */\n    if (!$cached_resource = $this->getResource()) {\n      return NULL;\n    }\n    if (!$cached_resource instanceof CacheDecoratedResourceInterface) {\n      return NULL;\n    }\n    return RenderCache::create($cache_fragments, $cached_resource->getCacheController());\n  }\n\n  /**\n   * Gets a cache fragments based on the data to be rendered.\n   *\n   * @param mixed $data\n   *   The data to be rendered.\n   *\n   * @return \\Doctrine\\Common\\Collections\\ArrayCollection;\n\n   *   The cache controller.\n   */\n  protected static function cacheFragments($data) {\n    $context = $data->getContext();\n    if (!$cache_fragments = $context['cache_fragments']) {\n      return NULL;\n    }\n    return $cache_fragments;\n  }\n\n  /**\n   * Returns only the allowed fields by filtering out the other ones.\n   *\n   * @param mixed $output\n   *   The data structure to filter.\n   * @param bool|string[] $allowed_fields\n   *   FALSE to allow all fields. An array of allowed values otherwise.\n   *\n   * @return mixed\n   *   The filtered output.\n   */\n  protected function limitFields($output, $allowed_fields = NULL) {\n    if (!isset($allowed_fields)) {\n      $request = ($resource = $this->getResource()) ? $resource->getRequest() : restful()->getRequest();\n      $input = $request->getParsedInput();\n      // Set the field limits to false if there are no limits.\n      $allowed_fields = empty($input['fields']) ? FALSE : explode(',', $input['fields']);\n    }\n    if (!is_array($output)) {\n      // $output is a simple value.\n      return $output;\n    }\n    $result = array();\n    if (ResourceFieldBase::isArrayNumeric($output)) {\n      foreach ($output as $item) {\n        $result[] = $this->limitFields($item, $allowed_fields);\n      }\n      return $result;\n    }\n    foreach ($output as $field_name => $field_contents) {\n      if ($allowed_fields !== FALSE && !in_array($field_name, $allowed_fields)) {\n        continue;\n      }\n      $result[$field_name] = $this->limitFields($field_contents, $this->unprefixInputOptions($allowed_fields, $field_name));\n    }\n    return $result;\n  }\n\n  /**\n   * Given a prefix, return the allowed fields that apply removing the prefix.\n   *\n   * @param bool|string[] $allowed_fields\n   *   The list of allowed fields in dot notation.\n   * @param string $prefix\n   *   The prefix used to select the fields and to remove from the front.\n   *\n   * @return bool|string[]\n   *   The new allowed fields for the nested sub-request.\n   */\n  protected static function unprefixInputOptions($allowed_fields, $prefix) {\n    if ($allowed_fields === FALSE) {\n      return FALSE;\n    }\n    $closure_unprefix = function ($field_limit) use ($prefix) {\n      if ($field_limit == $prefix) {\n        return NULL;\n      }\n      $pos = strpos($field_limit, $prefix . '.');\n      // Remove the prefix from the $field_limit.\n      return $pos === 0 ? substr($field_limit, strlen($prefix . '.')) : NULL;\n    };\n    return array_filter(array_map($closure_unprefix, $allowed_fields));\n  }\n\n\n  /**\n   * Helper function that calculates the number of items per page.\n   *\n   * @param ResourceInterface $resource\n   *   The associated resource.\n   *\n   * @return int\n   *   The items per page.\n   */\n  protected function calculateItemsPerPage(ResourceInterface $resource) {\n    $data_provider = $resource->getDataProvider();\n    $max_range = $data_provider->getRange();\n    $original_input = $resource->getRequest()->getPagerInput();\n    $items_per_page = empty($original_input['size']) ? $max_range : $original_input['size'];\n    return $items_per_page > $max_range ? $max_range : $items_per_page;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/formatter/FormatterHalJson.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\FormatterHalJson.\n */\n\nnamespace Drupal\\restful\\Plugin\\formatter;\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldResourceInterface;\n\n/**\n * Class FormatterHalJson\n * @package Drupal\\restful\\Plugin\\formatter\n *\n * @Formatter(\n *   id = \"hal_json\",\n *   label = \"HAL+JSON\",\n *   description = \"Output in using the HAL conventions and JSON format.\",\n *   curie = {\n *     \"name\": \"hal\",\n *     \"path\": \"doc/rels\",\n *     \"template\": \"/{rel}\",\n *   },\n * )\n */\nclass FormatterHalJson extends Formatter implements FormatterInterface {\n\n  const CURIE_SEPARATOR = ':';\n\n  /**\n   * Content Type\n   *\n   * @var string\n   */\n  protected $contentType = 'application/hal+json; charset=utf-8';\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare(array $data) {\n    // If we're returning an error then set the content type to\n    // 'application/problem+json; charset=utf-8'.\n    if (!empty($data['status']) && floor($data['status'] / 100) != 2) {\n      $this->contentType = 'application/problem+json; charset=utf-8';\n      return $data;\n    }\n    // Here we get the data after calling the backend storage for the resources.\n    if (!$resource = $this->getResource()) {\n      throw new ServerConfigurationException('Resource unavailable for HAL formatter.');\n    }\n    $is_list_request = $resource->getRequest()->isListRequest($resource->getPath());\n\n    $values = $this->extractFieldValues($data);\n    $values = $this->limitFields($values);\n    if ($is_list_request) {\n      // If this is a listing, move everything into the _embedded.\n      $curies_resource = $this->withCurie($resource->getResourceMachineName());\n      $output = array(\n        '_embedded' => array($curies_resource => $values),\n      );\n    }\n    else {\n      $output = reset($values) ?: array();\n    }\n\n    $data_provider = $resource->getDataProvider();\n    if (\n      $data_provider &&\n      method_exists($data_provider, 'count') &&\n      $is_list_request\n    ) {\n      // Get the total number of items for the current request without\n      // pagination.\n      $output['count'] = $data_provider->count();\n    }\n    if (method_exists($resource, 'additionalHateoas')) {\n      $output = array_merge($output, $resource->additionalHateoas());\n    }\n\n    // Add HATEOAS to the output.\n    $this->addHateoas($output);\n\n    // Cosmetic sorting to send the hateoas properties to the end of the output.\n    uksort($output, function ($a, $b) {\n      if (\n        ($a[0] == '_' && $b[0] == '_') ||\n        ($a[0] != '_' && $b[0] != '_')\n      ) {\n        return strcmp($a, $b);\n      }\n      return $a[0] == '_' ? 1 : -1;\n    });\n\n    return $output;\n  }\n\n  /**\n   * Add HATEOAS links to list of item.\n   *\n   * @param array $data\n   *   The data array after initial massaging.\n   */\n  protected function addHateoas(array &$data) {\n    if (!$resource = $this->getResource()) {\n      return;\n    }\n    $request = $resource->getRequest();\n\n    if (!isset($data['_links'])) {\n      $data['_links'] = array();\n    }\n\n    // Get self link.\n    $data['_links']['self'] = array(\n      'title' => 'Self',\n      'href' => $resource->versionedUrl($resource->getPath()),\n    );\n\n    $input = $request->getPagerInput();\n    $page = $input['number'];\n\n    if ($page > 1) {\n      $input['number'] = $page - 1;\n      $data['_links']['previous'] = array(\n        'title' => 'Previous',\n        'href' => $resource->getUrl(),\n      );\n    }\n\n    $curies_resource = $this->withCurie($resource->getResourceMachineName());\n    $listed_items = empty($data['_embedded'][$curies_resource]) ? 1 : count($data['_embedded'][$curies_resource]);\n\n    // We know that there are more pages if the total count is bigger than the\n    // number of items of the current request plus the number of items in\n    // previous pages.\n    $items_per_page = $this->calculateItemsPerPage($resource);\n    $previous_items = ($page - 1) * $items_per_page;\n    if (isset($data['count']) && $data['count'] > $listed_items + $previous_items) {\n      $input['number'] = $page + 1;\n      $data['_links']['next'] = array(\n        'title' => 'Next',\n        'href' => $resource->getUrl(),\n      );\n    }\n\n    if (!$curie = $this->getCurie()) {\n      return;\n    }\n\n    $curie += array(\n      'path' => 'doc/rels',\n      'template' => '/{rel}',\n    );\n    $data['_links']['curies'] = array(\n      'name' => $curie['name'],\n      'href' => url($curie['path'], array('absolute' => TRUE)) . $curie['template'],\n      'templated' => TRUE,\n    );\n  }\n\n  /**\n   * Extracts the actual values from the resource fields.\n   *\n   * @param array|\\Traversable|\\stdClass $data\n   *   The array of rows.\n   *\n   * @return array[]\n   *   The array of prepared data.\n   *\n   * @throws \\Drupal\\restful\\Exception\\InternalServerErrorException\n   */\n  protected function extractFieldValues($data, array $parents = array(), array &$parent_hashes = array()) {\n    $output = array();\n    if ($this->isCacheEnabled($data)) {\n      $parent_hashes[] = $this->getCacheHash($data);\n      if ($cache = $this->getCachedData($data)) {\n        return $cache->data;\n      }\n    }\n    foreach ($data as $public_field_name => $resource_field) {\n      if (!$resource_field instanceof ResourceFieldInterface) {\n        // If $resource_field is not a ResourceFieldInterface it means that we\n        // are dealing with a nested structure of some sort. If it is an array\n        // we process it as a set of rows, if not then use the value directly.\n        $parents[] = $public_field_name;\n        $output[$public_field_name] = static::isIterable($resource_field) ? $this->extractFieldValues($resource_field, $parents, $parent_hashes) : $resource_field;\n        continue;\n      }\n      if (!$data instanceof ResourceFieldCollectionInterface) {\n        throw new InternalServerErrorException('Inconsistent output.');\n      }\n\n      // This feels a bit awkward, but if the result is going to be cached, it\n      // pays off the extra effort of generating the whole resource entity. That\n      // way we can get a different field set with the previously cached entity.\n      // If the entity is not going to be cached, then avoid generating the\n      // field data altogether.\n      $limit_fields = $data->getLimitFields();\n      if (\n        $this->isCacheEnabled($data) &&\n        $limit_fields &&\n        !in_array($resource_field->getPublicName(), $limit_fields)\n      ) {\n        // We are not going to cache this and this field is not in the output.\n        continue;\n      }\n      $value = $resource_field->render($data->getInterpreter());\n      // If the field points to a resource that can be included, include it\n      // right away.\n      if (\n        static::isIterable($value)\n        && $resource_field instanceof ResourceFieldResourceInterface\n      ) {\n        $output += array('_embedded' => array());\n        $output['_embedded'][$this->withCurie($public_field_name)] = $this->extractFieldValues($value, $parents, $parent_hashes);\n        continue;\n      }\n      $output[$public_field_name] = $value;\n    }\n    if ($this->isCacheEnabled($data)) {\n      $this->setCachedData($data, $output, $parent_hashes);\n    }\n    return $output;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(array $structured_data) {\n    return drupal_json_encode($structured_data);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getContentTypeHeader() {\n    return $this->contentType;\n  }\n\n  /**\n   * Prefix a property name with the curie, if present.\n   *\n   * @param string $property_name\n   *   The input string.\n   *\n   * @return string\n   *   The property name prefixed with the curie.\n   */\n  protected function withCurie($property_name) {\n    if ($curie = $this->getCurie()) {\n      return $property_name ? $curie['name'] . static::CURIE_SEPARATOR . $property_name : $curie['name'];\n    }\n    return $property_name;\n  }\n\n  /**\n   * Checks if the current plugin has a defined curie.\n   *\n   * @return array\n   *   Associative array with the curie information.\n   */\n  protected function getCurie() {\n    return $this->configuration['curie'];\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/formatter/FormatterInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\FormatterInterface\n */\n\nnamespace Drupal\\restful\\Plugin\\formatter;\n\nuse Drupal\\Component\\Plugin\\ConfigurablePluginInterface;\nuse Drupal\\Component\\Plugin\\PluginInspectionInterface;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\ninterface FormatterInterface extends PluginInspectionInterface, ConfigurablePluginInterface {\n\n  /**\n   * Massages the raw data to create a structured array to pass to the renderer.\n   *\n   * @param ResourceFieldInterface[] $data\n   *   The raw data to return.\n   *\n   * @return array\n   *   The data prepared to be rendered.\n   */\n  public function prepare(array $data);\n\n  /**\n   * Renders an array in the selected format.\n   *\n   * @param array $structured_data\n   *   The data prepared to be rendered as returned by\n   *   \\RestfulFormatterInterface::prepare().\n   *\n   * @return string\n   *   The body contents for the HTTP response.\n   */\n  public function render(array $structured_data);\n\n  /**\n   * Formats the un-structured data into the output format.\n   *\n   * @param array $data\n   *   The raw data to return.\n   *\n   * @return string\n   *   The body contents for the HTTP response.\n   *\n   * @see \\RestfulFormatterInterface::prepare()\n   * @see \\RestfulFormatterInterface::render()\n   */\n  public function format(array $data);\n\n  /**\n   * Returns the content type for the selected output format.\n   *\n   * @return string\n   *   The contents for the ContentType header in the response.\n   */\n  public function getContentTypeHeader();\n\n  /**\n   * Gets the underlying resource.\n   *\n   * @return ResourceInterface\n   *   The resource.\n   */\n  public function getResource();\n\n  /**\n   * Sets the underlying resource.\n   *\n   * @param ResourceInterface $resource\n   *   The resource to set.\n   */\n  public function setResource(ResourceInterface $resource);\n\n  /**\n   * Parses the body string into the common format.\n   *\n   * @param string $body\n   *   The string sent from the consumer.\n   *\n   * @return array\n   *   The parsed object following the expected structure.\n   *\n   * @throws \\Drupal\\restful\\Exception\\ServerConfigurationException\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   */\n  public function parseBody($body);\n\n}\n"
  },
  {
    "path": "src/Plugin/formatter/FormatterJson.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\FormatterJson.\n */\n\nnamespace Drupal\\restful\\Plugin\\formatter;\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldResourceInterface;\n\n/**\n * Class FormatterHalJson.\n *\n * @package Drupal\\restful\\Plugin\\formatter\n *\n * @Formatter(\n *   id = \"json\",\n *   label = \"Simple JSON\",\n *   description = \"Output in using the JSON format.\"\n * )\n */\nclass FormatterJson extends Formatter implements FormatterInterface {\n\n  /**\n   * Content Type.\n   *\n   * @var string\n   */\n  protected $contentType = 'application/json; charset=utf-8';\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare(array $data) {\n    // If we're returning an error then set the content type to\n    // 'application/problem+json; charset=utf-8'.\n    if (!empty($data['status']) && floor($data['status'] / 100) != 2) {\n      $this->contentType = 'application/problem+json; charset=utf-8';\n      return $data;\n    }\n\n    $extracted = $this->extractFieldValues($data);\n    $output = array('data' => $this->limitFields($extracted));\n\n    if ($resource = $this->getResource()) {\n      $request = $resource->getRequest();\n      $data_provider = $resource->getDataProvider();\n      if ($request->isListRequest($resource->getPath())) {\n        // Get the total number of items for the current request without\n        // pagination.\n        $output['count'] = $data_provider->count();\n        // If there are items that were taken out during access checks,\n        // report them as denied in the metadata.\n        if (variable_get('restful_show_access_denied', FALSE) && ($inaccessible_records = $data_provider->getMetadata()->get('inaccessible_records'))) {\n          $output['denied'] = empty($output['meta']['denied']) ? $inaccessible_records : $output['meta']['denied'] + $inaccessible_records;\n        }\n      }\n      if (method_exists($resource, 'additionalHateoas')) {\n        $output = array_merge($output, $resource->additionalHateoas($output));\n      }\n\n      // Add HATEOAS to the output.\n      $this->addHateoas($output);\n    }\n\n    return $output;\n  }\n\n  /**\n   * Extracts the actual values from the resource fields.\n   *\n   * @param array[]|ResourceFieldCollectionInterface $data\n   *   The array of rows or a ResourceFieldCollection.\n   * @param string[] $parents\n   *   An array that holds the name of the parent fields that lead to the\n   *   current data structure.\n   * @param string[] $parent_hashes\n   *   An array that holds the name of the parent cache hashes that lead to the\n   *   current data structure.\n   *\n   * @return array[]\n   *   The array of prepared data.\n   *\n   * @throws InternalServerErrorException\n   */\n  protected function extractFieldValues($data, array $parents = array(), array &$parent_hashes = array()) {\n    $output = array();\n    if ($this->isCacheEnabled($data)) {\n      $parent_hashes[] = $this->getCacheHash($data);\n      if ($cache = $this->getCachedData($data)) {\n        return $cache->data;\n      }\n    }\n    foreach ($data as $public_field_name => $resource_field) {\n      if (!$resource_field instanceof ResourceFieldInterface) {\n        // If $resource_field is not a ResourceFieldInterface it means that we\n        // are dealing with a nested structure of some sort. If it is an array\n        // we process it as a set of rows, if not then use the value directly.\n        $parents[] = $public_field_name;\n        $output[$public_field_name] = static::isIterable($resource_field) ? $this->extractFieldValues($resource_field, $parents, $parent_hashes) : $resource_field;\n        continue;\n      }\n      if (!$data instanceof ResourceFieldCollectionInterface) {\n        throw new InternalServerErrorException('Inconsistent output.');\n      }\n\n      // This feels a bit awkward, but if the result is going to be cached, it\n      // pays off the extra effort of generating the whole resource entity. That\n      // way we can get a different field set with the previously cached entity.\n      // If the entity is not going to be cached, then avoid generating the\n      // field data altogether.\n      $limit_fields = $data->getLimitFields();\n      if (\n        !$this->isCacheEnabled($data) &&\n        $limit_fields &&\n        !in_array($resource_field->getPublicName(), $limit_fields)\n      ) {\n        // We are not going to cache this and this field is not in the output.\n        continue;\n      }\n      $value = $resource_field->render($data->getInterpreter());\n      // If the field points to a resource that can be included, include it\n      // right away.\n      if (\n        static::isIterable($value) &&\n        $resource_field instanceof ResourceFieldResourceInterface\n      ) {\n        $value = $this->extractFieldValues($value, $parents, $parent_hashes);\n      }\n      $output[$public_field_name] = $value;\n    }\n    if ($this->isCacheEnabled($data)) {\n      $this->setCachedData($data, $output, $parent_hashes);\n    }\n    return $output;\n  }\n\n  /**\n   * Add HATEOAS links to list of item.\n   *\n   * @param array $data\n   *   The data array after initial massaging.\n   */\n  protected function addHateoas(array &$data) {\n    if (!$resource = $this->getResource()) {\n      return;\n    }\n    $request = $resource->getRequest();\n\n    // Get self link.\n    $data['self'] = array(\n      'title' => 'Self',\n      'href' => $resource->versionedUrl($resource->getPath()),\n    );\n\n    $input = $request->getParsedInput();\n    unset($input['page']);\n    unset($input['range']);\n    $input['page'] = $request->getPagerInput();\n    $page = $input['page']['number'];\n\n    if ($page > 1) {\n      $query = $input;\n      $query['page']['number'] = $page - 1;\n      $data['previous'] = array(\n        'title' => 'Previous',\n        'href' => $resource->versionedUrl('', array('query' => $query), TRUE),\n      );\n    }\n\n    // We know that there are more pages if the total count is bigger than the\n    // number of items of the current request plus the number of items in\n    // previous pages.\n    $items_per_page = $this->calculateItemsPerPage($resource);\n    $previous_items = ($page - 1) * $items_per_page;\n    if (isset($data['count']) && $data['count'] > count($data['data']) + $previous_items) {\n      $query = $input;\n      $query['page']['number'] = $page + 1;\n      $data['next'] = array(\n        'title' => 'Next',\n        'href' => $resource->versionedUrl('', array('query' => $query), TRUE),\n      );\n    }\n\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(array $structured_data) {\n    return drupal_json_encode($structured_data);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getContentTypeHeader() {\n    return $this->contentType;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function parseBody($body) {\n    if (!$decoded_json = drupal_json_decode($body)) {\n      throw new BadRequestException(sprintf('Invalid JSON provided: %s.', $body));\n    }\n    return $decoded_json;\n  }\n\n}\n\n"
  },
  {
    "path": "src/Plugin/formatter/FormatterJsonApi.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\FormatterJsonApi.\n */\n\nnamespace Drupal\\restful\\Plugin\\formatter;\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class FormatterJsonApi\n * @package Drupal\\restful\\Plugin\\formatter\n *\n * @Formatter(\n *   id = \"json_api\",\n *   label = \"JSON API\",\n *   description = \"Output in using the JSON API format.\"\n * )\n */\nclass FormatterJsonApi extends Formatter implements FormatterInterface {\n\n  /**\n   * Content Type\n   *\n   * @var string\n   */\n  protected $contentType = 'application/vnd.api+json; charset=utf-8';\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare(array $data) {\n    // If we're returning an error then set the content type to\n    // 'application/problem+json; charset=utf-8'.\n    if (!empty($data['status']) && floor($data['status'] / 100) != 2) {\n      $this->contentType = 'application/problem+json; charset=utf-8';\n      return $data;\n    }\n\n    $extracted = $this->extractFieldValues($data);\n    $included = array();\n    $output = array('data' => $this->renormalize($extracted, $included));\n    $output = $this->populateIncludes($output, $included);\n\n    if ($resource = $this->getResource()) {\n      $request = $resource->getRequest();\n      $data_provider = $resource->getDataProvider();\n      $is_list_request = $request->isListRequest($resource->getPath());\n      if ($is_list_request) {\n        // Get the total number of items for the current request without\n        // pagination.\n        $output['meta']['count'] = $data_provider->count();\n        // If there are items that were taken out during access checks,\n        // report them as denied in the metadata.\n        if (variable_get('restful_show_access_denied', FALSE) && ($inaccessible_records = $data_provider->getMetadata()->get('inaccessible_records'))) {\n          $output['meta']['denied'] = empty($output['meta']['denied']) ? $inaccessible_records : $output['meta']['denied'] + $inaccessible_records;\n        }\n      }\n      else {\n        // For non-list requests do not return an array of one item.\n        $output['data'] = reset($output['data']);\n      }\n      if (method_exists($resource, 'additionalHateoas')) {\n        $output = array_merge($output, $resource->additionalHateoas($output));\n      }\n\n      // Add HATEOAS to the output.\n      $this->addHateoas($output);\n    }\n\n    return $output;\n  }\n\n  /**\n   * Extracts the actual values from the resource fields.\n   *\n   * @param array[]|ResourceFieldCollectionInterface $data\n   *   The array of rows or a ResourceFieldCollection.\n   * @param string[] $parents\n   *   An array that holds the name of the parent fields that lead to the\n   *   current data structure.\n   * @param string[] $parent_hashes\n   *   An array that holds the name of the parent cache hashes that lead to the\n   *   current data structure.\n   *\n   * @return array[]\n   *   The array of prepared data.\n   *\n   * @throws InternalServerErrorException\n   * @throws \\Drupal\\restful\\Exception\\ServerConfigurationException\n   */\n  protected function extractFieldValues($data, array $parents = array(), array $parent_hashes = array()) {\n    $output = array();\n    if ($this->isCacheEnabled($data)) {\n      $parent_hashes[] = $this->getCacheHash($data);\n      if ($cache = $this->getCachedData($data)) {\n        return $cache->data;\n      }\n    }\n    foreach ($data as $public_field_name => $resource_field) {\n      if (!$resource_field instanceof ResourceFieldInterface) {\n        // If $resource_field is not a ResourceFieldInterface it means that we\n        // are dealing with a nested structure of some sort. If it is an array\n        // we process it as a set of rows, if not then use the value directly.\n        $parents[] = $public_field_name;\n        $output[$public_field_name] = static::isIterable($resource_field) ? $this->extractFieldValues($resource_field, $parents, $parent_hashes) : $resource_field;\n        continue;\n      }\n      if (!$data instanceof ResourceFieldCollectionInterface) {\n        throw new InternalServerErrorException('Inconsistent output.');\n      }\n\n      // This feels a bit awkward, but if the result is going to be cached, it\n      // pays off the extra effort of generating the whole resource entity. That\n      // way we can get a different field set with the previously cached entity.\n      // If the entity is not going to be cached, then avoid generating the\n      // field data altogether.\n      $limit_fields = $data->getLimitFields();\n      $output['#fields'] = empty($output['#fields']) ? array() : $output['#fields'];\n      if (\n        !$this->isCacheEnabled($data) &&\n        $limit_fields &&\n        !in_array($resource_field->getPublicName(), $limit_fields)\n      ) {\n        // We are not going to cache this and this field is not in the output.\n        continue;\n      }\n      $interpreter = $data->getInterpreter();\n      if (!$id_field = $data->getIdField()) {\n        throw new ServerConfigurationException('Invalid required ID field for JSON API formatter.');\n      }\n      $output['#fields'][$public_field_name] = $this->embedField($resource_field, $id_field->render($interpreter), $interpreter, $parents, $parent_hashes);\n    }\n\n    if ($data instanceof ResourceFieldCollectionInterface) {\n      $output['#resource_name'] = $data->getResourceName();\n      $output['#resource_plugin'] = $data->getResourceId();\n      $resource_id = $data->getIdField()->render($data->getInterpreter());\n      if (!is_array($resource_id)) {\n        // In some situations when making an OPTIONS call the $resource_id\n        // returns the array of discovery information instead of a real value.\n        $output['#resource_id'] = (string) $resource_id;\n        try {\n          $output['#links']['self'] = restful()\n            ->getResourceManager()\n            ->getPlugin($output['#resource_plugin'])\n            ->versionedUrl($output['#resource_id']);\n        }\n        catch(PluginNotFoundException $e) {}\n      }\n    }\n    if ($this->isCacheEnabled($data)) {\n      $this->setCachedData($data, $output, $parent_hashes);\n    }\n    return $output;\n  }\n\n  /**\n   * Add HATEOAS links to list of item.\n   *\n   * @param array $data\n   *   The data array after initial massaging.\n   * @param ResourceInterface $resource\n   *   The resource to use.\n   * @param string $path\n   *   The resource path.\n   */\n  protected function addHateoas(array &$data, ResourceInterface $resource = NULL, $path = NULL) {\n    $top_level = empty($resource);\n    $resource = $resource ?: $this->getResource();\n    $path = isset($path) ? $path : $resource->getPath();\n    if (!$resource) {\n      return;\n    }\n    $request = $resource->getRequest();\n\n    if (!isset($data['links'])) {\n      $data['links'] = array();\n    }\n\n    $input = $original_input = $request->getParsedInput();\n    unset($input['page']);\n    unset($input['range']);\n    unset($original_input['page']);\n    unset($original_input['range']);\n    $input['page'] = $request->getPagerInput();\n    $original_input['page'] = $request->getPagerInput();\n\n    // Get self link.\n    $options = $top_level ? array('query' => $input) : array();\n    $data['links']['self'] = $resource->versionedUrl($path, $options);\n\n    $page = $input['page']['number'];\n\n    // We know that there are more pages if the total count is bigger than the\n    // number of items of the current request plus the number of items in\n    // previous pages.\n    $items_per_page = $this->calculateItemsPerPage($resource);\n    if (isset($data['meta']['count']) && $data['meta']['count'] > $items_per_page) {\n      $num_pages = ceil($data['meta']['count'] / $items_per_page);\n      unset($input['page']['number']);\n      $data['links']['first'] = $resource->getUrl(array('query' => $input), FALSE);\n\n      if ($page > 1) {\n        $input = $original_input;\n        $input['page']['number'] = $page - 1;\n        $data['links']['previous'] = $resource->getUrl(array('query' => $input), FALSE);\n      }\n      if ($num_pages > 1) {\n        $input = $original_input;\n        $input['page']['number'] = $num_pages;\n        $data['links']['last'] = $resource->getUrl(array('query' => $input), FALSE);\n        if ($page != $num_pages) {\n          $input = $original_input;\n          $input['page']['number'] = $page + 1;\n          $data['links']['next'] = $resource->getUrl(array('query' => $input), FALSE);\n        }\n      }\n    }\n\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(array $structured_data) {\n    return drupal_json_encode($structured_data);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getContentTypeHeader() {\n    return $this->contentType;\n  }\n\n  /**\n   * Gets the request object for this formatter.\n   *\n   * @return RequestInterface\n   *   The request object.\n   */\n  protected function getRequest() {\n    if ($resource = $this->getResource()) {\n      return $resource->getRequest();\n    }\n    return restful()->getRequest();\n  }\n\n  /**\n   * Move the embedded resources to the included key.\n   *\n   * Change the data structure from an auto-contained hierarchical tree to the\n   * final JSON API structure. The auto-contained tree has redundant information\n   * because every branch contains all the information that is embedded in there\n   * and can be used as stand alone.\n   *\n   * @param array $output\n   *   The output array to modify to include the compounded documents.\n   * @param array $included\n   *   Pool of documents to compound.\n   * @param bool|string[] $allowed_fields\n   *   The sparse fieldset information. FALSE to select all fields.\n   * @param array $includes_parents\n   *   An array containing the included path until the current field being\n   *   processed.\n   *\n   * @return array\n   *   The processed data.\n   */\n  protected function renormalize(array $output, array &$included, $allowed_fields = NULL, $includes_parents = array()) {\n    static $depth = -1;\n    $depth++;\n    if (!isset($allowed_fields)) {\n      $request = ($resource = $this->getResource()) ? $resource->getRequest() : restful()->getRequest();\n      $input = $request->getParsedInput();\n      // Set the field limits to false if there are no limits.\n      $allowed_fields = empty($input['fields']) ? FALSE : explode(',', $input['fields']);\n    }\n    if (!is_array($output)) {\n      // $output is a simple value.\n      $depth--;\n      return $output;\n    }\n    $result = array();\n    if (ResourceFieldBase::isArrayNumeric($output)) {\n      foreach ($output as $item) {\n        $result[] = $this->renormalize($item, $included, $allowed_fields, $includes_parents);\n      }\n      $depth--;\n      return $result;\n    }\n    if (!empty($output['#resource_name'])) {\n      $result['type'] = $output['#resource_name'];\n    }\n    if (!empty($output['#resource_id'])) {\n      $result['id'] = $output['#resource_id'];\n    }\n    if (!isset($output['#fields'])) {\n      $depth--;\n      return $this->renormalize($output, $included, $allowed_fields, $includes_parents);\n    }\n    foreach ($output['#fields'] as $field_name => $field_contents) {\n      if ($allowed_fields !== FALSE && !in_array($field_name, $allowed_fields)) {\n        continue;\n      }\n      if (empty($field_contents['#embedded'])) {\n        $result['attributes'][$field_name] = $field_contents;\n      }\n      else {\n        // Handle single and multiple relationships.\n        $rel = array();\n        $single_item = $field_contents['#cardinality'] == 1;\n        $relationship_links = empty($field_contents['#relationship_links']) ? NULL : $field_contents['#relationship_links'];\n        unset($field_contents['#embedded']);\n        unset($field_contents['#cardinality']);\n        unset($field_contents['#relationship_links']);\n        foreach ($field_contents as $field_item) {\n          $include_links = empty($field_item['#include_links']) ? NULL : $field_item['#include_links'];\n          unset($field_contents['#include_links']);\n          $field_path = $this->buildIncludePath($includes_parents, $field_name);\n          $field_item = $this->populateCachePlaceholder($field_item, $field_path);\n          unset($field_item['#cache_placeholder']);\n          $element = $field_item['#relationship_info'];\n          unset($field_item['#relationship_info']);\n          $include_key = $field_item['#resource_plugin'] . '--' . $field_item['#resource_id'];\n          $nested_allowed_fields = $this->unprefixInputOptions($allowed_fields, $field_name);\n          // If the list of the child allowed fields is empty, but the parent is\n          // part of the includes, it means that the consumer meant to include\n          // all the fields in the children.\n          if (is_array($allowed_fields) && empty($nested_allowed_fields) && in_array($field_name, $allowed_fields)) {\n            $nested_allowed_fields = FALSE;\n          }\n          // If we get here is because the relationship is included in the\n          // sparse fieldset. That means that in this context, empty field\n          // limits mean all the fields.\n          $new_includes_parents = $includes_parents;\n          $new_includes_parents[] = $field_name;\n          $included[$field_path][$include_key] = $this->renormalize($field_item, $included, $nested_allowed_fields, $new_includes_parents);\n          $included[$field_path][$include_key] += $include_links ? array('links' => $include_links) : array();\n          $rel[$include_key] = $element;\n        }\n        // Only place the relationship info.\n        $result['relationships'][$field_name] = array(\n          'data' => $single_item ? reset($rel) : array_values($rel),\n        );\n        if (!empty($relationship_links)) {\n          $result['relationships'][$field_name]['links'] = $relationship_links;\n        }\n      }\n    }\n    // Set the links for every item.\n    if (!empty($output['#links'])) {\n      $result['links'] = $output['#links'];\n    }\n\n    // Decrease the depth level.\n    $depth--;\n    return $result;\n  }\n\n  /**\n   * Gather all of the includes.\n   */\n  protected function populateIncludes($output, $included) {\n    // Loop through the included resource entities and add them to the output if\n    // they are included from the request.\n    $input = $this->getRequest()->getParsedInput();\n    $requested_includes = empty($input['include']) ? array() : explode(',', $input['include']);\n    // Keep track of everything that has been included.\n    $included_keys = array();\n    foreach ($requested_includes as $requested_include) {\n      if (empty($included[$requested_include])) {\n        continue;\n      }\n      foreach ($included[$requested_include] as $include_key => $included_item) {\n        if (in_array($include_key, $included_keys)) {\n          continue;\n        }\n        $output['included'][] = $included_item;\n        $included_keys[] = $include_key;\n      }\n    }\n    return $output;\n  }\n\n  /**\n   * Embeds the final contents of a field.\n   *\n   * If the field is a relationship to another resource, it embeds the resource.\n   *\n   * @param ResourceFieldInterface $resource_field\n   *   The resource field being processed. If it is a related resource, this is\n   *   used to extract the contents of the resource. If not, it's used to\n   *   extract the simple value.\n   * @param string $parent_id\n   *   ID in the parent resource where this is being embedded.\n   * @param DataInterpreterInterface $interpreter\n   *   The context for the $resource_field.\n   * @param array $parents\n   *   Tracks the parents of the field to construct the dot notation for the\n   *   field name.\n   * @param string[] $parent_hashes\n   *   An array that holds the name of the parent cache hashes that lead to the\n   *   current data structure.\n   *\n   * @return array\n   *   The contents for the JSON API attribute or relationship.\n   */\n  protected function embedField(ResourceFieldInterface $resource_field, $parent_id, DataInterpreterInterface $interpreter, array &$parents, array &$parent_hashes) {\n    static $embedded_resources = array();\n    // If the field points to a resource that can be included, include it\n    // right away.\n    if (!$resource_field instanceof ResourceFieldResourceInterface) {\n      return $resource_field->render($interpreter);\n    }\n    // Check if the resource needs to be included. If not then set 'full_view'\n    // to false.\n    $cardinality = $resource_field->getCardinality();\n    $output = array();\n    $public_field_name = $resource_field->getPublicName();\n    if (!$ids = $resource_field->compoundDocumentId($interpreter)) {\n      return NULL;\n    }\n    $ids = $cardinality == 1 ? $ids = array($ids) : $ids;\n    $resource_info = $resource_field->getResource();\n    $empty_value = array(\n      '#fields' => array(),\n      '#embedded' => TRUE,\n      '#resource_plugin' => sprintf('%s:%d.%d', $resource_info['name'], $resource_info['majorVersion'], $resource_info['minorVersion']),\n      '#cache_placeholder' => array(\n        'parents' => array_merge($parents, array($public_field_name)),\n        'parent_hashes' => $parent_hashes,\n      ),\n    );\n    $value = array_map(function ($id) use ($empty_value) {\n      return $empty_value + array('#resource_id' => $id);\n    }, $ids);\n    if ($this->needsIncluding($resource_field, $parents)) {\n      $cid = sprintf('%s:%d.%d--%s', $resource_info['name'], $resource_info['majorVersion'], $resource_info['minorVersion'], implode(',', $ids));\n      if (!isset($embedded_resources[$cid])) {\n        $result = $resource_field->render($interpreter);\n        if (empty($result) || !static::isIterable($result)) {\n          $embedded_resources[$cid] = $result;\n          return $result;\n        }\n        $new_parents = $parents;\n        $new_parents[] = $public_field_name;\n        $result = $this->extractFieldValues($result, $new_parents, $parent_hashes);\n        $embedded_resources[$cid] = $cardinality == 1 ? array($result) : $result;\n      }\n      $value = $embedded_resources[$cid];\n    }\n    // At this point we are dealing with an embed.\n    $value = array_filter($value);\n    // Set the resource for the reference.\n    $resource_plugin = $resource_field->getResourcePlugin();\n    foreach ($value as $value_item) {\n      $id = $value_item['#resource_id'];\n      $basic_info = array(\n        'type' => $resource_field->getResourceMachineName(),\n        'id' => (string) $id,\n      );\n\n      // We want to be able to include only the images in articles.images,\n      // but not articles.related.images. That's why we need the path\n      // including the parents.\n      $item = array(\n        '#resource_name' => $basic_info['type'],\n        '#resource_plugin' => $resource_plugin->getPluginId(),\n        '#resource_id' => $basic_info['id'],\n        '#include_links' => array(\n          'self' => $resource_plugin->versionedUrl($basic_info['id']),\n        ),\n        '#relationship_info' => array(\n          'type' => $basic_info['type'],\n          'id' => $basic_info['id'],\n        ),\n      ) + $value_item;\n      $output[] = $item;\n    }\n    // If there is a resource plugin for the parent, set the related\n    // links.\n    $links = array();\n    if ($resource = $this->getResource()) {\n      $links['related'] = $resource->versionedUrl('', array(\n        'absolute' => TRUE,\n        'query' => array(\n          'filter' => array($public_field_name => reset($ids)),\n        ),\n      ));\n      $links['self'] = $resource_plugin->versionedUrl($parent_id . '/relationships/' . $public_field_name);\n    }\n\n    return $output + array(\n      '#embedded' => TRUE,\n      '#cardinality' => $cardinality,\n      '#relationship_links' => $links,\n    );\n  }\n\n  /**\n   * Checks if a resource field needs to be embedded in the response.\n   *\n   * @param ResourceFieldResourceInterface $resource_field\n   *   The embedded resource field.\n   * @param array $parents\n   *   The parents of this embedded resource.\n   *\n   * @return bool\n   *   TRUE if the field needs including. FALSE otherwise.\n   */\n  protected function needsIncluding(ResourceFieldResourceInterface $resource_field, $parents) {\n    $input = $this->getRequest()->getParsedInput();\n    $includes = empty($input['include']) ? array() : explode(',', $input['include']);\n    return in_array($this->buildIncludePath($parents, $resource_field->getPublicName()), $includes);\n  }\n\n  /**\n   * Build the dot notation path for an array of parents.\n   *\n   * Remove numeric parents since those only indicate that the field was\n   * multivalue, not a parent: articles[related][1][tags][2][name] turns into\n   * 'articles.related.tags.name'.\n   *\n   * @param array $parents\n   *   The nested parents.\n   * @param string $public_field_name\n   *   The field name.\n   *\n   * @return string\n   *   The path.\n   */\n  protected function buildIncludePath(array $parents, $public_field_name = NULL) {\n    $array_path = $parents;\n    if ($public_field_name) {\n      array_push($array_path, $public_field_name);\n    }\n    $include_path = implode('.', array_filter($array_path, function ($item) {\n      return !is_numeric($item);\n    }));\n    return $include_path;\n  }\n\n  /**\n   * Given a field item that contains a cache placeholder render and cache it.\n   *\n   * @param array $field_item\n   *   The output to render.\n   *\n   * @param string $includes_path\n   *   The includes path encoded in dot notation.\n   *\n   * @return array\n   *   The rendered embedded field item.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\InternalServerErrorException\n   */\n  protected function populateCachePlaceholder(array $field_item, $includes_path) {\n    if (\n      empty($field_item['#cache_placeholder']) ||\n      empty($field_item['#resource_id']) ||\n      empty($field_item['#resource_plugin'])\n    ) {\n      return $field_item;\n    }\n    $embedded_resource = restful()\n      ->getResourceManager()\n      ->getPluginCopy($field_item['#resource_plugin']);\n    $input = $this->getRequest()->getParsedInput();\n    $new_input = $input + array('include' => '', 'fields' => '');\n    // If the field is not supposed to be included, then bail.\n    $old_includes = array_filter(explode(',', $new_input['include']));\n    if (!in_array($includes_path, $old_includes)) {\n      return $field_item;\n    }\n    $new_input['fields'] = implode(',', $this->unprefixInputOptions(explode(',', $new_input['fields']), $includes_path));\n    $new_input['include'] = implode(',', $this->unprefixInputOptions($old_includes, $includes_path));\n    // Create a new request from scratch copying most of the values but the\n    // $query.\n    $embedded_resource->setRequest(Request::create(\n      $this->getRequest()->getPath(),\n      array_filter($new_input),\n      $this->getRequest()->getMethod(),\n      $this->getRequest()->getHeaders(),\n      $this->getRequest()->isViaRouter(),\n      $this->getRequest()->getCsrfToken(),\n      $this->getRequest()->getCookies(),\n      $this->getRequest()->getFiles(),\n      $this->getRequest()->getServer(),\n      $this->getRequest()->getParsedBody()\n    ));\n    try {\n      $data = $embedded_resource->getDataProvider()\n        ->view($field_item['#resource_id']);\n    }\n    catch (InaccessibleRecordException $e) {\n      // Populate it with an empty element.\n      $data = array();\n    }\n    return array_merge(\n      $field_item,\n      $this->extractFieldValues($data, $field_item['#cache_placeholder']['parents'], $field_item['#cache_placeholder']['parent_hashes'])\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function parseBody($body) {\n    if (!$decoded_json = drupal_json_decode($body)) {\n      throw new BadRequestException(sprintf('Invalid JSON provided: %s.', $body));\n    }\n    if (empty($decoded_json['data'])) {\n      throw new BadRequestException(sprintf('Invalid JSON provided: %s.', $body));\n    }\n    $data = $decoded_json['data'];\n    $includes = empty($decoded_json['included']) ? array() : $decoded_json['included'];\n    // It's always weird to deal with lists of items vs a single item.\n    $single_item = !ResourceFieldBase::isArrayNumeric($data);\n    // Make sure we're always dealing with a list of items.\n    $data = $single_item ? array($data) : $data;\n    $output = array();\n    foreach ($data as $item) {\n      $output[] = $this::restructureItem($item, $includes);\n    }\n\n    return $single_item ? reset($output) : $output;\n  }\n\n  /**\n   * Take a JSON API item and makes it hierarchical object, like simple JSON.\n   *\n   * @param array $item\n   *   The JSON API item.\n   * @param array $included\n   *   The included pool of elements.\n   *\n   * @return array\n   *   The hierarchical object.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   */\n  protected static function restructureItem(array $item, array $included) {\n    if (empty($item['meta']['subrequest']) && empty($item['attributes']) && empty($item['relationship'])) {\n      throw new BadRequestException('Invalid JSON provided: both attributes and relationship are empty.');\n    }\n    // Make sure that the attributes and relationships are accessible.\n    $element = empty($item['attributes']) ? array() : $item['attributes'];\n    $relationships = empty($item['relationships']) ? array() : $item['relationships'];\n    // For every relationship we need to see if it was included.\n    foreach ($relationships as $field_name => $relationship) {\n      if (empty($relationship['data'])) {\n        throw new BadRequestException('Invalid JSON provided: relationship without data.');\n      }\n      $data = $relationship['data'];\n      // It's always weird to deal with lists of items vs a single item.\n      $single_item = !ResourceFieldBase::isArrayNumeric($data);\n      // Make sure we're always dealing with a list of items.\n      $data = $single_item ? array($data) : $data;\n      $element[$field_name] = array();\n      foreach ($data as $info_pair) {\n        // Validate the JSON API structure for a relationship.\n        if (empty($info_pair['type'])) {\n          throw new BadRequestException('Invalid JSON provided: relationship item without type.');\n        }\n        if (empty($info_pair['id'])) {\n          throw new BadRequestException('Invalid JSON provided: relationship item without id.');\n        }\n        // Initialize the object if empty.\n        if (\n          !empty($info_pair['meta']['subrequest']) &&\n          $included_item = static::retrieveIncludedItem($info_pair['type'], $info_pair['id'], $included)\n        ) {\n          // If the relationship was included, restructure it and embed it.\n          $value = array(\n            'body' => static::restructureItem($included_item, $included),\n            'id' => $info_pair['id'],\n            'request' => $info_pair['meta']['subrequest'],\n          );\n          if (!empty($value['request']['method']) && $value['request']['method'] == RequestInterface::METHOD_POST) {\n            // If the value is a POST remove the ID, since we already\n            // retrieved the included item.\n            unset($value['id']);\n          }\n          $element[$field_name][] = $value;\n        }\n        else {\n          // If the include could not be retrieved, use the ID instead.\n          $element[$field_name][] = array('id' => $info_pair['id']);\n        }\n      }\n      // Make the single relationships to be a single item or a single ID.\n      $element[$field_name] = $single_item ? reset($element[$field_name]) : $element[$field_name];\n    }\n    return $element;\n  }\n\n  /**\n   * Retrieves an item from the included pool of items.\n   *\n   * @param string $type\n   *   The resource type.\n   * @param string $id\n   *   The resource identifier.\n   * @param array $included\n   *   All the available included elements.\n   *\n   * @return array\n   *   The JSON API element.\n   */\n  protected static function retrieveIncludedItem($type, $id, array $included) {\n    foreach ($included as $item) {\n      if (\n        !empty($item['type']) &&\n        $item['type'] == $type &&\n        !empty($item['id']) &&\n        $item['id'] == $id\n      ) {\n        return $item;\n      }\n    }\n    return NULL;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/formatter/FormatterSingleJson.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\formatter\\FormatterSingleJson.\n */\n\nnamespace Drupal\\restful\\Plugin\\formatter;\n\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase;\n\n/**\n * Class FormatterSingleJson\n * @package Drupal\\restful\\Plugin\\formatter\n *\n * @Formatter(\n *   id = \"single_json\",\n *   label = \"Single JSON\",\n *   description = \"Output a single item using the JSON format.\"\n * )\n */\nclass FormatterSingleJson extends FormatterJson {\n\n  /**\n   * Content Type\n   *\n   * @var string\n   */\n  protected $contentType = 'application/drupal.single+json; charset=utf-8';\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare(array $data) {\n    // If we're returning an error then set the content type to\n    // 'application/problem+json; charset=utf-8'.\n    if (!empty($data['status']) && floor($data['status'] / 100) != 2) {\n      $this->contentType = 'application/problem+json; charset=utf-8';\n      return $data;\n    }\n\n    $extracted = $this->extractFieldValues($data);\n    $output = $this->limitFields($extracted);\n    // Force returning a single item.\n    $output = ResourceFieldBase::isArrayNumeric($output) ? reset($output) : $output;\n\n    return $output ?: array();\n  }\n\n}\n\n"
  },
  {
    "path": "src/Plugin/rate_limit/RateLimit.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\rate_limit\\RateLimit\n */\n\nnamespace Drupal\\restful\\Plugin\\rate_limit;\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\RateLimit\\RateLimitManager;\n\nabstract class RateLimit extends PluginBase implements RateLimitInterface {\n\n  /**\n   * @var array\n   *\n   * Array of maximum limit of requests across all endpoints per role.\n   */\n  protected $limits = array();\n\n  /**\n   * @var \\DateInterval\n   *\n   * Period after which the rate limit is expired.\n   */\n  protected $period;\n\n  /**\n   * @var \\RestfulBase\n   *\n   * The resource this object is limiting access to.\n   */\n  protected $resource;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n    try {\n      $this->period = new \\DateInterval($configuration['period']);\n    }\n    catch (\\Exception $e) {\n      throw new ServerConfigurationException(sprintf('Invalid rate limit period: %s. Should be a valid format of \\DateInterval.', $configuration['period']));\n    }\n    $this->limits = $configuration['limits'];\n    $this->resource = $configuration['resource'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setLimit($limits) {\n    $this->limits = $limits;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getLimit($account = NULL) {\n    // If the user is anonymous.\n    if (empty($account->roles)) {\n      return $this->limits['anonymous user'];\n    }\n    // If the user is logged then return the best limit for all the roles the\n    // user has.\n    $max_limit = 0;\n    foreach ($account->roles as $rid => $role) {\n      if (!isset($this->limits[$role])) {\n        // No limit configured for this role.\n        continue;\n      }\n      if ($this->limits[$role] < $max_limit &&\n        $this->limits[$role] != RateLimitManager::UNLIMITED_RATE_LIMIT) {\n        // The limit is smaller than one previously found.\n        continue;\n      }\n      // This is the highest limit for the current user given all their roles.\n      $max_limit = $this->limits[$role];\n    }\n    return $max_limit;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPeriod(\\DateInterval $period) {\n    $this->period = $period;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPeriod() {\n    return $this->period;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function generateIdentifier($account = NULL) {\n    $identifier = $this->resource->getResourceName() . PluginBase::DERIVATIVE_SEPARATOR;\n    if ($this->getPluginId() == 'global') {\n      // Don't split the id by resource if the event is global.\n      $identifier = '';\n    }\n    $identifier .= $this->getPluginId() . PluginBase::DERIVATIVE_SEPARATOR;\n    $identifier .= empty($account->uid) ? ip_address() : $account->uid;\n    return $identifier;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function loadRateLimitEntity($account = NULL) {\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', 'rate_limit')\n      ->entityCondition('bundle', $this->getPluginId())\n      ->propertyCondition('identifier', $this->generateIdentifier($account))\n      ->execute();\n    if (empty($results['rate_limit'])) {\n      return NULL;\n    }\n    $rlid = key($results['rate_limit']);\n    return entity_load_single('rate_limit', $rlid);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/rate_limit/RateLimitGlobal.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\rate_limit\\RateLimitGlobal\n */\n\nnamespace Drupal\\restful\\Plugin\\rate_limit;\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Http\\RequestInterface;\n\n/**\n * Class RateLimitGlobal\n * @package Drupal\\restful\\Plugin\\rate_limit\n *\n * @RateLimit(\n *   id = \"global\",\n *   label = \"Global limitation\",\n *   description = \"This keeps a count across all the handlers.\",\n * )\n */\nclass RateLimitGlobal extends RateLimit {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n    $limit = variable_get('restful_global_rate_limit', 0);\n    foreach (user_roles() as $rid => $role_info) {\n      $this->limits[$rid] = $limit;\n    }\n    $this->period = new \\DateInterval(variable_get('restful_global_rate_period', 'P1D'));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function generateIdentifier($account = NULL) {\n    $identifier = '';\n    $identifier .= $this->getPluginId() . PluginBase::DERIVATIVE_SEPARATOR;\n    $identifier .= empty($account->uid) ? ip_address() : $account->uid;\n    return $identifier;\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * All limits are the same for the global limit. Return the first one.\n   */\n  public function getLimit($account = NULL) {\n    return reset($this->limits);\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * Only track the global limit for the current user if the variable is on.\n   */\n  public function isRequestedEvent(RequestInterface $request) {\n    return $this->getLimit() > 0;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/rate_limit/RateLimitInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\rate_limit\\RateLimitInterface\n */\n\nnamespace Drupal\\restful\\Plugin\\rate_limit;\n\nuse Drupal\\Component\\Plugin\\PluginInspectionInterface;\nuse Drupal\\restful\\Http\\RequestInterface;\n\ninterface RateLimitInterface extends PluginInspectionInterface {\n  /**\n   * Checks if the current request meets the event for the implementing class.\n   *\n   * @param RequestInterface $request\n   *   (optional) The request array.\n   *\n   * @return bool\n   *   TRUE if the event is met and the rate limit hits counter should be\n   *   incremented.\n   */\n  public function isRequestedEvent(RequestInterface $request);\n\n\n  /**\n   * Set the rate limit.\n   *\n   * @param array $limits\n   *   The limits to set.\n   */\n  public function setLimit($limits);\n\n  /**\n   * Get the rate limit. Returns the highest rate limit for the current account.\n   *\n   * @param object $account\n   *   The account object for the user making the request.\n   *\n   * @return int\n   *   The limit.\n   */\n  public function getLimit($account = NULL);\n\n  /**\n   * Set the rate limit period.\n   *\n   * @param \\DateInterval $period\n   */\n  public function setPeriod(\\DateInterval $period);\n\n  /**\n   * Get the rate limit period.\n   *\n   * @return \\DateInterval\n   *   The period.\n   */\n  public function getPeriod();\n\n  /**\n   * Generates an identifier for the event and the request.\n   *\n   * @param object $account\n   *   The account object for the user making the request.\n   *\n   * @return string\n   *   The ID.\n   */\n  public function generateIdentifier($account = NULL);\n\n  /**\n   * Load rate limit entity.\n   *\n   * @param object $account\n   *   The account object for the user making the request.\n   *\n   * @return RateLimitInterface\n   *   The loaded entity or NULL if none found.\n   */\n  public function loadRateLimitEntity($account = NULL);\n\n}\n"
  },
  {
    "path": "src/Plugin/rate_limit/RateLimitRequest.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\rate_limit\\RateLimitRequest\n */\n\nnamespace Drupal\\restful\\Plugin\\rate_limit;\nuse Drupal\\restful\\Http\\RequestInterface;\n\n/**\n * Class RateLimitGlobal\n * @package Drupal\\restful\\Plugin\\rate_limit\n *\n * @RateLimit(\n *   id = \"request\",\n *   label = \"Any request\",\n *   description = \"The basic rate limit plugin. Every call to a resource is counted.\",\n * )\n */\nclass RateLimitRequest extends RateLimit {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isRequestedEvent(RequestInterface $request) {\n    return TRUE;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/AuthenticatedResource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\AuthenticatedResource\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Authentication\\AuthenticationManager;\nuse Drupal\\restful\\Exception\\NotImplementedException;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\n\nclass AuthenticatedResource extends PluginBase implements AuthenticatedResourceInterface {\n\n  /**\n   * The decorated resource.\n   *\n   * @var ResourceInterface\n   */\n  protected $subject;\n\n  /**\n   * Authentication manager.\n   *\n   * @var AuthenticationManager\n   */\n  protected $authenticationManager;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAuthenticationManager(AuthenticationManager $authentication_manager) {\n    $this->authenticationManager = $authentication_manager;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAuthenticationManager() {\n    return $this->authenticationManager;\n  }\n\n  /**\n   * Data provider factory.\n   *\n   * @return DataProviderInterface\n   *   The data provider for this resource.\n   *\n   * @throws NotImplementedException\n   */\n  public function dataProviderFactory() {\n    return $this->subject->dataProviderFactory();\n  }\n\n  /**\n   * Proxy method to get the account from the authenticationManager.\n   *\n   * {@inheritdoc}\n   */\n  public function getAccount($cache = TRUE) {\n    // The request.\n    $request = $this->subject->getRequest();\n\n    $account = $this->getAuthenticationManager()->getAccount($request, $cache);\n\n    return $account;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->subject->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPath() {\n    return $this->subject->getPath();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFieldDefinitions() {\n    return $this->subject->getFieldDefinitions();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDataProvider() {\n    return $this->subject->getDataProvider();\n  }\n\n  /**\n   * Constructs a Drupal\\Component\\Plugin\\PluginBase object.\n   *\n   * @param ResourceInterface $subject\n   *   The decorated object.\n   * @param AuthenticationManager $auth_manager\n   *   (optional) Injected authentication manager.\n   */\n  public function __construct(ResourceInterface $subject, AuthenticationManager $auth_manager = NULL) {\n    $this->subject = $subject;\n    $this->authenticationManager = $auth_manager ? $auth_manager : new AuthenticationManager();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function process() {\n    return $this->subject->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function controllersInfo() {\n    return $this->subject->controllersInfo();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getControllers() {\n    return $this->subject->getControllers();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceName() {\n    return $this->subject->getResourceName();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index($path) {\n    return $this->subject->index($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($path) {\n    return $this->subject->view($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($path) {\n    return $this->subject->create($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($path) {\n    return $this->subject->update($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function replace($path) {\n    return $this->subject->replace($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($path) {\n    $this->subject->remove($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getVersion() {\n    return $this->subject->getVersion();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/AuthenticatedResourceInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\AuthenticatedResourceInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\Component\\Plugin\\PluginInspectionInterface;\nuse Drupal\\restful\\Authentication\\AuthenticationManager;\n\ninterface AuthenticatedResourceInterface extends PluginInspectionInterface {\n\n  /**\n   * Setter for $authenticationManager.\n   *\n   * @param AuthenticationManager $authentication_manager\n   *   The authentication manager.\n   */\n  public function setAuthenticationManager(AuthenticationManager $authentication_manager);\n\n  /**\n   * Getter for $authenticationManager.\n   *\n   * @return AuthenticationManager\n   *   The authentication manager.\n   */\n  public function getAuthenticationManager();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/CrudInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Resource\\CrudInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\ninterface CrudInterface {\n\n  /**\n   * List operation.\n   *\n   * @return array\n   *   An array of structured data for the things being viewed.\n   */\n  public function index();\n\n  /**\n   * Counts the total results for the index call.\n   *\n   * @return int\n   *   The total number of results for the index call.\n   */\n  public function count();\n\n  /**\n   * Create operation.\n   *\n   * @param mixed $object\n   *   The thing to be created.\n   *\n   * @return array\n   *   An array of structured data for the thing that was created.\n   */\n  public function create($object);\n\n  /**\n   * Read operation.\n   *\n   * @param mixed $identifier\n   *   The ID of thing being viewed.\n   *\n   * @return array\n   *   An array of data for the thing being viewed.\n   */\n  public function view($identifier);\n\n  /**\n   * Read operation.\n   *\n   * @param array $identifiers\n   *   The array of IDs of things being viewed.\n   *\n   * @return array\n   *   An array of structured data for the things being viewed.\n   */\n  public function viewMultiple(array $identifiers);\n\n  /**\n   * Update operation.\n   *\n   * @param mixed $identifier\n   *   The ID of thing to be updated.\n   * @param mixed $object\n   *   The thing that will be set.\n   * @param bool $replace\n   *   TRUE if the contents of $object will replace $identifier entirely. FALSE\n   *   if only what is set in $object will replace those properties in\n   *   $identifier.\n   *\n   * @return array\n   *   An array of structured data for the thing that was updated.\n   */\n  public function update($identifier, $object, $replace = FALSE);\n\n  /**\n   * Delete operation.\n   *\n   * @param mixed $identifier\n   *   The ID of thing to be removed.\n   */\n  public function remove($identifier);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/CsrfToken.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\CsrfToken.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\n/**\n * Class CsrfToken\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"csrf_token:1.0\",\n *   resource = \"csrf_token\",\n *   label = \"CSRF Token\",\n *   description = \"Resource that provides CSRF Tokens when using cookie authentication.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = FALSE,\n *   formatter = \"single_json\",\n *   renderCache = {\n *     \"render\": FALSE\n *   },\n *   menuItem = \"session/token\",\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass CsrfToken extends Resource implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    return array(\n      'X-CSRF-Token' => array(\n        'callback' => '\\Drupal\\restful\\Plugin\\resource\\CsrfToken::getCsrfToken',\n      ),\n    );\n  }\n\n  /**\n   * Value callback; Return the CSRF token.\n   *\n   * @return string\n   *   The token.\n   */\n  public static function getCsrfToken() {\n    return drupal_get_token(\\Drupal\\restful\\Plugin\\authentication\\Authentication::TOKEN_VALUE);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index($path) {\n    $values = array();\n    foreach ($this->publicFields() as $public_property => $info) {\n      $value = NULL;\n\n      if ($info['callback']) {\n        $value = ResourceManager::executeCallback($info['callback']);\n      }\n\n      if ($value && !empty($info['process_callbacks'])) {\n        foreach ($info['process_callbacks'] as $process_callback) {\n          $value = ResourceManager::executeCallback($process_callback, array($value));\n        }\n      }\n\n      $values[$public_property] = $value;\n    }\n\n    return $values;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/ArrayWrapper.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\ArrayWrapper.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\nclass ArrayWrapper implements ArrayWrapperInterface {\n\n  /**\n   * Plugin configuration.\n   *\n   * @var array\n   */\n  protected $data = array();\n\n  /**\n   * Constructs a PluginWrapper object.\n   *\n   * @param array $data\n   *   The array to wrap\n   */\n  public function __construct(array $data) {\n    $this->data = $data;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get($key) {\n    return isset($this->data[$key]) ? $this->data[$key] : NULL;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/ArrayWrapperInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\ArrayWrapperInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\ninterface ArrayWrapperInterface {\n\n  /**\n   * Gets a field from the data array.\n   *\n   * @param string $key\n   *   The key to get.\n   *\n   * @return mixed\n   *   The value.\n   */\n  public function get($key);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/DataInterpreterArray.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterArray.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\nclass DataInterpreterArray extends DataInterpreterBase implements DataInterpreterInterface {}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/DataInterpreterBase.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreter.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\nabstract class DataInterpreterBase implements DataInterpreterInterface {\n\n  /**\n   * The account.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * The wrapper.\n   *\n   * @var mixed\n   */\n  protected $wrapper;\n\n  /**\n   * Constructs a DataInterpreter object.\n   *\n   * @param object $account\n   *   The fully loaded object.\n   * @param mixed $wrapper\n   *   The container wrapper.\n   */\n  public function __construct($account, $wrapper) {\n    $this->account = $account;\n    $this->wrapper = $wrapper;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount() {\n    return $this->account;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getWrapper() {\n    return $this->wrapper;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/DataInterpreterEMW.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreter.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\nclass DataInterpreterEMW extends DataInterpreterBase implements DataInterpreterInterface {\n\n  /**\n   * Returns the \\EntityDrupalWrapper.\n   *\n   * @return \\EntityDrupalWrapper\n   *   The wrapper describing the entity.\n   */\n  public function getWrapper() {\n    // Note: this is just implemented to override the docblock. Now when we call\n    // DataInterpreterEMW::getWrapper we know we are getting a\n    // \\EntityDrupalWrapper object back.\n    return parent::getWrapper();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/DataInterpreterInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\ninterface DataInterpreterInterface {\n\n  /**\n   * Get the account.\n   *\n   * @return object\n   *   The fully loaded account.\n   */\n  public function getAccount();\n\n  /**\n   * Get the wrapper.\n   *\n   * @return mixed\n   *   The entity metadata wrapper describing the entity. Every data source will\n   *   return a different wrapper type. For instance a data source for entities\n   *   will return an \\EntityDrupalWrapper, a data source for DB query will\n   *   return a DatabaseColumnWrapper, etc.\n   */\n  public function getWrapper();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/DataInterpreterPlug.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterPlug.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\nclass DataInterpreterPlug extends DataInterpreterBase implements DataInterpreterInterface {}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/PluginWrapper.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\PluginWrapper.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\nuse Drupal\\Component\\Plugin\\ConfigurablePluginInterface;\nuse Drupal\\Component\\Plugin\\PluginInspectionInterface;\n\nclass PluginWrapper implements PluginWrapperInterface {\n\n  /**\n   * Plugin configuration.\n   *\n   * @var array\n   */\n  protected $pluginConfiguration = array();\n\n  /**\n   * Plugin definition.\n   *\n   * @var array\n   */\n  protected $pluginDefinition = array();\n\n  /**\n   * Plugin instance.\n   *\n   * @var PluginInspectionInterface\n   */\n  protected $plugin;\n\n  /**\n   * Constructs a PluginWrapper object.\n   *\n   * @param PluginInspectionInterface $plugin\n   *   The plugin to wrap.\n   */\n  public function __construct(PluginInspectionInterface $plugin) {\n    $this->plugin = $plugin;\n    $this->pluginDefinition = $plugin->getPluginDefinition();\n    // For configurable plugins, expose those properties as well.\n    if ($plugin instanceof ConfigurablePluginInterface) {\n      $this->pluginConfiguration = $plugin->getConfiguration();\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get($key) {\n    // If there is a key by that name in the plugin configuration return it, if\n    // not then check the plugin definition. If it cannot be found, return NULL.\n    $value = isset($this->pluginConfiguration[$key]) ? $this->pluginConfiguration[$key] : NULL;\n    return $value ? $value : (isset($this->pluginDefinition[$key]) ? $this->pluginDefinition[$key] : NULL);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataInterpreter/PluginWrapperInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\PluginWrapperInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataInterpreter;\n\n\ninterface PluginWrapperInterface {\n\n  /**\n   * Gets a field from the plugin configuration.\n   *\n   * @param string $key\n   *   The key to get.\n   *\n   * @return mixed\n   *   The value.\n   */\n  public function get($key);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/CacheDecoratedDataProvider.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\CacheDecoratedDataProvider.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\RenderCache\\RenderCache;\nuse Drupal\\restful\\Util\\ExplorableDecoratorInterface;\n\n/**\n * Class CacheDecoratedDataProvider.\n *\n * @package Drupal\\restful\\Plugin\\resource\\DataProvider\n */\nclass CacheDecoratedDataProvider implements CacheDecoratedDataProviderInterface, ExplorableDecoratorInterface {\n\n  /**\n   * The decorated object.\n   *\n   * @var DataProviderInterface\n   */\n  protected $subject;\n\n  /**\n   * The cache controller to interact with the cache backed.\n   *\n   * @var \\DrupalCacheInterface\n   */\n  protected $cacheController;\n\n  /**\n   * Constructs a CacheDecoratedDataProvider object.\n   *\n   * @param DataProviderInterface $subject\n   *   The data provider to add caching to.\n   * @param \\DrupalCacheInterface $cache_controller\n   *   The cache controller to add the cache.\n   */\n  public function __construct(DataProviderInterface $subject, \\DrupalCacheInterface $cache_controller) {\n    $this->subject = $subject;\n    $this->cacheController = $cache_controller;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isNestedField($field_name) {\n    return DataProvider::isNestedField($field_name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function processFilterInput($filter, $public_field) {\n    return DataProvider::processFilterInput($filter, $public_field);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function discover($path = NULL) {\n    return $this->subject->discover($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRange() {\n    return $this->subject->getRange();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRange($range) {\n    return $this->subject->setRange($range);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount() {\n    return $this->subject->getAccount();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->subject->setAccount($account);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->subject->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->subject->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getLangCode() {\n    return $this->subject->getLangCode();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setLangCode($langcode) {\n    $this->subject->setLangCode($langcode);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getOptions() {\n    return $this->subject->getOptions();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addOptions(array $options) {\n    $this->subject->addOptions($options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheFragments($identifier) {\n    return $this->subject->getCacheFragments($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index() {\n    // TODO: This is duplicating the code from DataProvider::index\n    $ids = $this->getIndexIds();\n\n    return $this->viewMultiple($ids);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    return $this->subject->getIndexIds();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return $this->subject->count();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    return $this->subject->create($object);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    $resource_field_collection = $this->subject->view($identifier);\n    if (!$resource_field_collection instanceof ResourceFieldCollectionInterface) {\n      return NULL;\n    }\n\n    $resource_field_collection->setContext('cache_fragments', $this->getCacheFragments($identifier));\n    return $resource_field_collection;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    $return = array();\n    // If no IDs were requested, we should not throw an exception in case an\n    // entity is un-accessible by the user.\n    foreach ($identifiers as $identifier) {\n      try {\n        $row = $this->view($identifier);\n      }\n      catch (InaccessibleRecordException $e) {\n        $row = NULL;\n      }\n      $return[] = $row;\n    }\n\n    return array_values(array_filter($return));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = TRUE) {\n    $this->clearRenderedCache($this->getCacheFragments($identifier));\n    return $this->subject->update($identifier, $object, $replace);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    $this->clearRenderedCache($this->getCacheFragments($identifier));\n    $this->subject->remove($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function methodAccess(ResourceFieldInterface $resource_field) {\n    $this->subject->methodAccess($resource_field);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function canonicalPath($path) {\n    return $this->subject->canonicalPath($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setOptions(array $options) {\n    $this->subject->setOptions($options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResourcePath($resource_path) {\n    $this->subject->setResourcePath($resource_path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourcePath() {\n    return $this->subject->getResourcePath();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMetadata() {\n    return $this->subject->getMetadata();\n  }\n\n  /**\n   * Clears the cache entries related to the given cache fragments.\n   *\n   * @param \\Doctrine\\Common\\Collections\\ArrayCollection $cache_fragments\n   *   The cache fragments to clear.\n   */\n  protected function clearRenderedCache(ArrayCollection $cache_fragments) {\n    $cache_object = new RenderCache($cache_fragments, NULL, $this->cacheController);\n    $cache_object->clear();\n  }\n\n  /**\n   * Checks if the decorated object is an instance of something.\n   *\n   * @param string $class\n   *   Class or interface to check the instance.\n   *\n   * @return bool\n   *   TRUE if the decorated object is an instace of the $class. FALSE\n   *   otherwise.\n   */\n  public function isInstanceOf($class) {\n    if ($this instanceof $class || $this->subject instanceof $class) {\n      return TRUE;\n    }\n    // Check if the decorated resource is also a decorator.\n    if ($this->subject instanceof ExplorableDecoratorInterface) {\n      return $this->subject->isInstanceOf($class);\n    }\n    return FALSE;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/CacheDecoratedDataProviderInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful\\Plugin\\resource\\DataProvider\\CacheDecoratedDataProviderInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Exception\\NotImplementedException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\ninterface CacheDecoratedDataProviderInterface extends DataProviderInterface {}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProvider.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProvider.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\nuse Drupal\\restful\\Http\\HttpHeader;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoBase;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\n\nabstract class DataProvider implements DataProviderInterface {\n\n  /**\n   * The field definitions.\n   *\n   * @var ResourceFieldCollectionInterface\n   */\n  protected $fieldDefinitions;\n\n  /**\n   * The request\n   *\n   * @var RequestInterface\n   */\n  protected $request;\n\n  /**\n   * Determines the number of items that should be returned when viewing lists.\n   *\n   * @var int\n   */\n  protected $range = 50;\n\n  /**\n   * The account authenticated from the request for entity access checks.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * Determines the language of the items that should be returned.\n   *\n   * @var string\n   */\n  protected $langcode;\n\n  /**\n   * User defined options.\n   *\n   * @var array\n   */\n  protected $options = array();\n\n  /**\n   * The resource path.\n   *\n   * @var string\n   */\n  protected $resourcePath;\n\n  /**\n   * Array of metadata. Use this as a mean to pass info to the render layer.\n   *\n   * @var ArrayCollection\n   */\n  protected $metadata;\n\n  /**\n   * Resource identifier.\n   *\n   * @var string\n   */\n  protected $pluginId;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function processFilterInput($filter, $public_field) {\n    // Filtering can be achieved in different ways:\n    // 1. filter[foo]=bar\n    // 2. filter[foo][0]=bar&filter[foo][1]=baz\n    // 3. filter[foo][value]=bar\n    // 4. filter[foo][value][0]=bar&filter[foo][value][1]=baz\n    if (!is_array($filter)) {\n      // Request uses the shorthand form for filter. For example\n      // filter[foo]=bar would be converted to filter[foo][value] = bar.\n      $filter = array('value' => $filter);\n    }\n    if (!isset($filter['value'])) {\n      throw new BadRequestException(sprintf('Value not present for the \"%s\" filter. Please check the URL format.', $public_field));\n    }\n    if (!is_array($filter['value'])) {\n      $filter['value'] = array($filter['value']);\n    }\n    // Add the property.\n    $filter['public_field'] = $public_field;\n\n    // Set default operator.\n    $filter += array('operator' => array_fill(0, count($filter['value']), '='));\n    if (!is_array($filter['operator'])) {\n      $filter['operator'] = array($filter['operator']);\n    }\n\n    // Make sure that we have the same amount of operators than values.\n    $first_operator = strtoupper($filter['operator'][0]);\n    if (!in_array($first_operator, array(\n        'IN',\n        'NOT IN',\n        'BETWEEN',\n      )) && count($filter['value']) != count($filter['operator'])\n    ) {\n      throw new BadRequestException('The number of operators and values has to be the same.');\n    }\n    // Make sure that the BETWEEN operator gets only 2 values.\n    if ($first_operator == 'BETWEEN' && count($filter['value']) != 2) {\n      throw new BadRequestException('The BETWEEN operator takes exactly 2 values.');\n    }\n\n    $filter += array('conjunction' => 'AND');\n\n    // Clean the operator in case it came from the URL.\n    // e.g. filter[minor_version][operator][0]=\">=\"\n    // str_replace will process all the elements in the array.\n    $filter['operator'] = str_replace(array('\"', \"'\"), '', $filter['operator']);\n\n    static::isValidOperatorsForFilter($filter['operator']);\n    static::isValidConjunctionForFilter($filter['conjunction']);\n    return $filter;\n  }\n\n  /**\n   * Constructor.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   * @param ResourceFieldCollectionInterface $field_definitions\n   *   The field definitions.\n   * @param object $account\n   *   The authenticated account.\n   * @param string $plugin_id\n   *   The resource ID.\n   * @param string $resource_path\n   *   The resource path.\n   * @param array $options\n   *   The plugin options for the data provider.\n   * @param string $langcode\n   *   (Optional) The entity language code.\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path = NULL, array $options = array(), $langcode = NULL) {\n    $this->request = $request;\n    $this->fieldDefinitions = $field_definitions;\n    $this->account = $account;\n    $this->pluginId = $plugin_id;\n    $this->options = $options;\n    $this->resourcePath = $resource_path;\n    if (!empty($options['range'])) {\n      // TODO: Document that the range is now overridable in the annotation.\n      $this->range = $options['range'];\n    }\n    $this->langcode = $langcode ?: static::getLanguage();\n    $this->metadata = new ArrayCollection();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRange() {\n    return $this->range;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRange($range) {\n    $this->range = $range;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount() {\n    return $this->account;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->account = $account;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->request;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->request = $request;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getLangCode() {\n    return $this->langcode;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setLangCode($langcode) {\n    $this->langcode = $langcode;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getOptions() {\n    return $this->options;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setOptions(array $options) {\n    $this->options = $options;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addOptions(array $options) {\n    $this->options = array_merge($this->options, $options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheFragments($identifier) {\n    // If we are trying to get the context for multiple ids, join them.\n    if (is_array($identifier)) {\n      $identifier = implode(',', $identifier);\n    }\n    $fragments = new ArrayCollection(array(\n      'resource' => CacheDecoratedResource::serializeKeyValue($this->pluginId, $this->canonicalPath($identifier)),\n    ));\n    $options = $this->getOptions();\n    switch ($options['renderCache']['granularity']) {\n      case DRUPAL_CACHE_PER_USER:\n        if ($uid = $this->getAccount()->uid) {\n          $fragments->set('user_id', (int) $uid);\n        }\n        break;\n      case DRUPAL_CACHE_PER_ROLE:\n        $fragments->set('user_role', implode(',', $this->getAccount()->roles));\n        break;\n    }\n    return $fragments;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index() {\n    if (!$ids = $this->getIndexIds()) {\n      return array();\n    }\n\n    return $this->viewMultiple($ids);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function discover($path = NULL) {\n    // Alter the field definition by adding a callback to get the auto\n    // discover information in render time.\n    foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {\n      /* @var ResourceFieldInterface $resource_field */\n      if (method_exists($resource_field, 'autoDiscovery')) {\n        // Adding the autoDiscover method to the resource field class will allow\n        // you to be smarter about the auto discovery information.\n        $callable = array($resource_field, 'autoDiscovery');\n      }\n      else {\n        // If the given field does not have discovery information, provide the\n        // empty one instead of an error.\n        $callable = array('\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase::emptyDiscoveryInfo', array($public_field_name));\n      }\n      $resource_field->setCallback($callable);\n      // Remove the process callbacks, those don't make sense during discovery.\n      $resource_field->setProcessCallbacks(array());\n      $definition = $resource_field->getDefinition();\n      $discovery_info = empty($definition['discovery']) ? array() : $definition['discovery'];\n      $resource_field->setPublicFieldInfo(new PublicFieldInfoBase($resource_field->getPublicName(), $discovery_info));\n    }\n    return $path ? $this->viewMultiple(array($path)) : $this->index();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function canonicalPath($path) {\n    // Assume that there is no alias.\n    return $path;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function methodAccess(ResourceFieldInterface $resource_field) {\n    return in_array($this->getRequest()->getMethod(), $resource_field->getMethods());\n  }\n\n  /**\n   * Parses the request to get the sorting options.\n   *\n   * @return array\n   *   With the different sorting options.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\UnprocessableEntityException\n   */\n  protected function parseRequestForListSort() {\n    $input = $this->getRequest()->getParsedInput();\n\n    if (empty($input['sort'])) {\n      return array();\n    }\n\n    $url_params = $this->options['urlParams'];\n    if (!$url_params['sort']) {\n      throw new UnprocessableEntityException('Sort parameters have been disabled in server configuration.');\n    }\n\n    $sorts = array();\n    foreach (explode(',', $input['sort']) as $sort) {\n      $direction = $sort[0] == '-' ? 'DESC' : 'ASC';\n      $sort = str_replace('-', '', $sort);\n      // Check the sort is on a legal key.\n      if (!$this->fieldDefinitions->get($sort)) {\n        throw new BadRequestException(format_string('The sort @sort is not allowed for this path.', array('@sort' => $sort)));\n      }\n\n      $sorts[$sort] = $direction;\n    }\n    return $sorts;\n  }\n\n  /**\n   * Filter the query for list.\n   *\n   * @returns array\n   *   An array of filters to apply.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\UnprocessableEntityException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function parseRequestForListFilter() {\n    if (!$this->request->isListRequest($this->getResourcePath())) {\n      // Not a list request, so we don't need to filter.\n      // We explicitly check this, as this function might be called from a\n      // formatter plugin, after RESTful's error handling has finished, and an\n      // invalid key might be passed.\n      return array();\n    }\n    $input = $this->getRequest()->getParsedInput();\n    if (empty($input['filter'])) {\n      // No filtering is needed.\n      return array();\n    }\n\n    $url_params = empty($this->options['urlParams']) ? array() : $this->options['urlParams'];\n    if (isset($url_params['filter']) && !$url_params['filter']) {\n      throw new UnprocessableEntityException('Filter parameters have been disabled in server configuration.');\n    }\n\n    $filters = array();\n\n    foreach ($input['filter'] as $public_field => $value) {\n      if (!static::isNestedField($public_field) && !$this->fieldDefinitions->get($public_field)) {\n        throw new BadRequestException(format_string('The filter @filter is not allowed for this path.', array('@filter' => $public_field)));\n      }\n      $filter = static::processFilterInput($value, $public_field);\n      $filters[] = $filter + array('resource_id' => $this->pluginId);\n    }\n\n    return $filters;\n  }\n\n  /**\n   * Parses the request object to get the pagination options.\n   *\n   * @return array\n   *   A numeric array with the offset and length options.\n   *\n   * @throws BadRequestException\n   * @throws UnprocessableEntityException\n   */\n  protected function parseRequestForListPagination() {\n    $pager_input = $this->getRequest()->getPagerInput();\n\n    $page = isset($pager_input['number']) ? $pager_input['number'] : 1;\n    if (!ctype_digit((string) $page) || $page < 1) {\n      throw new BadRequestException('\"Page\" property should be numeric and equal or higher than 1.');\n    }\n\n    $range = isset($pager_input['size']) ? (int) $pager_input['size'] : $this->getRange();\n    $range = $range > $this->getRange() ? $this->getRange() : $range;\n    if (!ctype_digit((string) $range) || $range < 1) {\n      throw new BadRequestException('\"Range\" property should be numeric and equal or higher than 1.');\n    }\n\n    $url_params = empty($this->options['urlParams']) ? array() : $this->options['urlParams'];\n    if (isset($url_params['range']) && !$url_params['range']) {\n      throw new UnprocessableEntityException('Range parameters have been disabled in server configuration.');\n    }\n\n    $offset = ($page - 1) * $range;\n    return array($offset, $range);\n  }\n\n  /**\n   * Adds query tags and metadata to the EntityFieldQuery.\n   *\n   * @param \\EntityFieldQuery|\\SelectQuery $query\n   *   The query to enhance.\n   */\n  protected function addExtraInfoToQuery($query) {\n    // Add a generic tags to the query.\n    $query->addTag('restful');\n    $query->addMetaData('account', $this->getAccount());\n  }\n\n  /**\n   * Check if an operator is valid for filtering.\n   *\n   * @param array $operators\n   *   The array of operators.\n   *\n   * @throws BadRequestException\n   */\n  protected static function isValidOperatorsForFilter(array $operators) {\n    $allowed_operators = array(\n      '=',\n      '>',\n      '<',\n      '>=',\n      '<=',\n      '<>',\n      '!=',\n      'NOT IN',\n      'BETWEEN',\n      'CONTAINS',\n      'IN',\n      'NOT IN',\n      'STARTS_WITH',\n    );\n\n    foreach ($operators as $operator) {\n      if (!in_array($operator, $allowed_operators)) {\n        throw new BadRequestException(sprintf('Operator \"%s\" is not allowed for filtering on this resource. Allowed operators are: %s', $operator, implode(', ', $allowed_operators)));\n      }\n    }\n  }\n\n  /**\n   * Check if a conjunction is valid for filtering.\n   *\n   * @param string $conjunction\n   *   The operator.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   */\n  protected static function isValidConjunctionForFilter($conjunction) {\n    $allowed_conjunctions = array(\n      'AND',\n      'OR',\n      'XOR',\n    );\n\n    if (!in_array(strtoupper($conjunction), $allowed_conjunctions)) {\n      throw new BadRequestException(format_string('Conjunction \"@conjunction\" is not allowed for filtering on this resource. Allowed conjunctions are: !allowed', array(\n        '@conjunction' => $conjunction,\n        '!allowed' => implode(', ', $allowed_conjunctions),\n      )));\n    }\n  }\n\n  /**\n   * Gets the global language.\n   *\n   * @return string\n   *   The language code.\n   */\n  protected static function getLanguage() {\n    // Move to its own method to allow unit testing.\n    return $GLOBALS['language']->language;\n  }\n\n  /**\n   * Sets an HTTP header.\n   *\n   * @param string $name\n   *   The header name.\n   * @param string $value\n   *   The header value.\n   */\n  protected function setHttpHeader($name, $value) {\n    $this\n      ->getRequest()\n      ->getHeaders()\n      ->add(HttpHeader::create($name, $value));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResourcePath($resource_path) {\n    $this->resourcePath = $resource_path;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourcePath() {\n    return $this->resourcePath;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isNestedField($field_name) {\n    return strpos($field_name, '.') !== FALSE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMetadata() {\n    return $this->metadata;\n  }\n\n  /**\n   * Initialize the empty resource field collection to bundle the output.\n   *\n   * @param mixed $identifier\n   *   The ID of thing being viewed.\n   *\n   * @return ResourceFieldCollectionInterface\n   *   The collection of fields.\n   *\n   * @throws \\Drupal\\restful\\Exception\\NotFoundException\n   */\n  protected function initResourceFieldCollection($identifier) {\n    $resource_field_collection = new ResourceFieldCollection(array(), $this->getRequest());\n    $interpreter = $this->initDataInterpreter($identifier);\n    $resource_field_collection->setInterpreter($interpreter);\n    $id_field_name = empty($this->options['idField']) ? 'id' : $this->options['idField'];\n    $resource_field_collection->setIdField($this->fieldDefinitions->get($id_field_name));\n    $resource_field_collection->setResourceId($this->pluginId);\n    return $resource_field_collection;\n  }\n\n  /**\n   * Get the data interpreter.\n   *\n   * @param mixed $identifier\n   *   The ID of thing being viewed.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface\n   *   The data interpreter.\n   */\n  abstract protected function initDataInterpreter($identifier);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderDbQuery.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderDbQuery.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\ServiceUnavailableException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\ArrayWrapper;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterArray;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldDbColumnInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\nclass DataProviderDbQuery extends DataProvider implements DataProviderDbQueryInterface {\n\n  /**\n   * The name of the table to query.\n   *\n   * @var string\n   */\n  protected $tableName;\n  /**\n   * The name of the column(s) in the table to be used as the unique key.\n   *\n   * @var array\n   */\n  protected $idColumn;\n\n  /**\n   * The separator used to divide a key into its table columns when there is\n   * more than one column.\n   */\n  const COLUMN_IDS_SEPARATOR = '::';\n\n  /**\n   * Holds the primary field.\n   *\n   * @var string\n   */\n  protected $primary;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path = NULL, array $options = array(), $langcode = NULL) {\n    parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);\n    // Validate keys exist in the plugin's \"data provider options\".\n    $required_keys = array(\n      'tableName',\n      'idColumn',\n    );\n    $required_callback = function ($required_key) {\n      if (!$this->options[$required_key]) {\n        throw new ServiceUnavailableException(sprintf('%s is missing \"%s\" property in the \"dataProvider\" key of the $plugin', get_class($this), $required_key));\n      }\n    };\n    array_walk($required_keys, $required_callback);\n    $this->tableName = $this->options['tableName'];\n    $this->idColumn = $this->options['idColumn'];\n    $this->primary = empty($this->options['primary']) ? NULL : $this->primary = $this->options['primary'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getTableName() {\n    return $this->tableName;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setTableName($table_name) {\n    $this->tableName = $table_name;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPrimary() {\n    return $this->primary;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPrimary($primary) {\n    $this->primary = $primary;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheFragments($identifier) {\n    if (is_array($identifier)) {\n      // Like in https://example.org/api/articles/1,2,3.\n      $identifier = implode(ResourceInterface::IDS_SEPARATOR, $identifier);\n    }\n    $fragments = new ArrayCollection(array(\n      'resource' => CacheDecoratedResource::serializeKeyValue($this->pluginId, $this->canonicalPath($identifier)),\n      'table_name' => $this->getTableName(),\n      'column' => implode(',', $this->getIdColumn()),\n    ));\n    $options = $this->getOptions();\n    switch ($options['renderCache']['granularity']) {\n      case DRUPAL_CACHE_PER_USER:\n        if ($uid = $this->getAccount()->uid) {\n          $fragments->set('user_id', (int) $uid);\n        }\n        break;\n      case DRUPAL_CACHE_PER_ROLE:\n        $fragments->set('user_role', implode(',', $this->getAccount()->roles));\n        break;\n    }\n    return $fragments;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return intval($this\n      ->getQueryForList()\n      ->countQuery()\n      ->execute()\n      ->fetchField());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isPrimaryField($field_name) {\n    return $this->primary == $field_name;\n  }\n\n  /**\n   * Get ID column.\n   *\n   * @return array\n   *   An array with the name of the column(s) in the table to be used as the\n   *   unique key.\n   */\n  protected function getIdColumn() {\n    return is_array($this->idColumn) ? $this->idColumn : array($this->idColumn);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    $save = FALSE;\n    $original_object = $object;\n    $id_columns = $this->getIdColumn();\n    $record = array();\n    foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {\n      /* @var ResourceFieldDbColumnInterface $resource_field */\n      if (!$this->methodAccess($resource_field)) {\n        // Allow passing the value in the request.\n        unset($original_object[$public_field_name]);\n        continue;\n      }\n\n      $property_name = $resource_field->getProperty();\n      // If this is the primary field, skip.\n      if ($this->isPrimaryField($property_name)) {\n        unset($original_object[$public_field_name]);\n        continue;\n      }\n      if (isset($object[$public_field_name])) {\n        $record[$property_name] = $object[$public_field_name];\n      }\n      unset($original_object[$public_field_name]);\n      $save = TRUE;\n    }\n    // No request was sent.\n    if (!$save) {\n      throw new BadRequestException('No values were sent with the request.');\n    }\n    // If the original request is not empty, then illegal values are present.\n    if (!empty($original_object)) {\n      $error_message = format_plural(count($original_object), 'Property @names is invalid.', 'Property @names are invalid.', array('@names' => implode(', ', array_keys($original_object))));\n      throw new BadRequestException($error_message);\n    }\n    // Once the record is built, write it and view it.\n    if (drupal_write_record($this->getTableName(), $record)) {\n      // Handle multiple id columns.\n      $id_values = array();\n      foreach ($id_columns as $id_column) {\n        $id_values[$id_column] = $record[$id_column];\n      }\n      $new_id = implode(self::COLUMN_IDS_SEPARATOR, $id_values);\n      return array($this->view($new_id));\n    }\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    $query = $this->getQuery();\n    foreach ($this->getIdColumn() as $index => $column) {\n      $identifier = is_array($identifier) ? $identifier : array($identifier);\n      $query->condition($this->getTableName() . '.' . $column, current($this->getColumnFromIds($identifier, $index)));\n    }\n    $this->addExtraInfoToQuery($query);\n    $result = $query\n      ->range(0, 1)\n      ->execute()\n      ->fetch(\\PDO::FETCH_OBJ);\n    return $this->mapDbRowToPublicFields($result);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function mapDbRowToPublicFields($row) {\n    $resource_field_collection = $this->initResourceFieldCollection($row);\n\n    // Loop over all the defined public fields.\n    foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {\n      $value = NULL;\n      /* @var ResourceFieldDbColumnInterface $resource_field */\n      if (!$this->methodAccess($resource_field)) {\n        // Allow passing the value in the request.\n        continue;\n      }\n      $resource_field_collection->set($resource_field->id(), $resource_field);\n    }\n    return $resource_field_collection;\n  }\n\n  /**\n   * Adds query tags and metadata to the EntityFieldQuery.\n   *\n   * @param \\SelectQuery $query\n   *   The query to enhance.\n   */\n  protected function addExtraInfoToQuery($query) {\n    $query->addTag('restful');\n    $query->addMetaData('account', $this->getAccount());\n    $query->addMetaData('restful_handler', $this);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    // Get a list query with all the sorting and pagination in place.\n    $query = $this->getQueryForList();\n    if (empty($identifiers)) {\n      return array();\n    }\n    foreach ($this->getIdColumn() as $index => $column) {\n      $query->condition($this->getTableName() . '.' . $column, $this->getColumnFromIds($identifiers, $index), 'IN');\n    }\n    $results = $query->execute();\n    $return = array();\n    foreach ($results as $result) {\n      $return[] = $this->mapDbRowToPublicFields($result);\n    }\n    return $return;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function getQueryForList() {\n    $query = $this->getQuery();\n    $this->queryForListSort($query);\n    $this->queryForListFilter($query);\n    $this->queryForListPagination($query);\n    $this->addExtraInfoToQuery($query);\n    return $query;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    // Build the update array.\n    $save = FALSE;\n    $original_object = $object;\n    $id_columns = $this->getIdColumn();\n    $record = array();\n    foreach ($this->fieldDefinitions as $public_field_name => $resource_field) {\n      /* @var ResourceFieldDbColumnInterface $resource_field */\n      if (!$this->methodAccess($resource_field)) {\n        // Allow passing the value in the request.\n        unset($original_object[$public_field_name]);\n        continue;\n      }\n      $property = $resource_field->getProperty();\n      // If this is the primary field, skip.\n      if ($this->isPrimaryField($property)) {\n        continue;\n      }\n      if (isset($object[$public_field_name])) {\n        $record[$property] = $object[$public_field_name];\n      }\n      // For unset fields on full updates, pass NULL to drupal_write_record().\n      elseif ($replace) {\n        $record[$property] = NULL;\n      }\n      unset($original_object[$public_field_name]);\n      $save = TRUE;\n    }\n    // No request was sent.\n    if (!$save) {\n      throw new BadRequestException('No values were sent with the request.');\n    }\n    // If the original request is not empty, then illegal values are present.\n    if (!empty($original_object)) {\n      $error_message = format_plural(count($original_object), 'Property @names is invalid.', 'Property @names are invalid.', array('@names' => implode(', ', array_keys($original_object))));\n      throw new BadRequestException($error_message);\n    }\n    // Add the id column values into the record.\n    foreach ($this->getIdColumn() as $index => $column) {\n      $record[$column] = current($this->getColumnFromIds(array($identifier), $index));\n    }\n    // Once the record is built, write it.\n    if (!drupal_write_record($this->getTableName(), $record, $id_columns)) {\n      throw new ServiceUnavailableException('Record could not be updated to the database.');\n    }\n    return array($this->view($identifier));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    // If it's a delete method we will want a 204 response code.\n    // Set the HTTP headers.\n    $this->setHttpHeader('Status', 204);\n    $query = db_delete($this->getTableName());\n    foreach ($this->getIdColumn() as $index => $column) {\n      $query->condition($column, current($this->getColumnFromIds(array($identifier), $index)));\n    }\n    $query->execute();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    $results = $this\n      ->getQueryForList()\n      ->execute();\n    $ids = array();\n    foreach ($results as $result) {\n      $ids[] = array_map(function ($id_column) use ($result) {\n        return $result->{$id_column};\n      }, $this->getIdColumn());\n    }\n    return $ids;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index() {\n    $results = $this\n      ->getQueryForList()\n      ->execute();\n    $return = array();\n    foreach ($results as $result) {\n      $return[] = $this->mapDbRowToPublicFields($result);\n    }\n    return $return;\n  }\n\n  /**\n   * Defines default sort columns if none are provided via the request URL.\n   *\n   * @return array\n   *   Array keyed by the database column name, and the order ('ASC' or 'DESC')\n   *   as value.\n   */\n  protected function defaultSortInfo() {\n    $sorts = array();\n    foreach ($this->getIdColumn() as $column) {\n      if (!$this->fieldDefinitions->get($column)) {\n        // Sort by the first ID column that is a public field.\n        $sorts[$column] = 'ASC';\n        break;\n      }\n    }\n    return $sorts;\n  }\n\n  /**\n   * Sort the query for list.\n   *\n   * @param \\SelectQuery $query\n   *   The query object.\n   *\n   * @throws BadRequestException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function queryForListSort(\\SelectQuery $query) {\n    // Get the sorting options from the request object.\n    $sorts = $this->parseRequestForListSort();\n    $sorts = $sorts ? $sorts : $this->defaultSortInfo();\n    foreach ($sorts as $sort => $direction) {\n      /* @var ResourceFieldDbColumnInterface $sort_field */\n      if ($sort_field = $this->fieldDefinitions->get($sort)) {\n        $query->orderBy($sort_field->getColumnForQuery(), $direction);\n      }\n    }\n  }\n\n  /**\n   * Filter the query for list.\n   *\n   * @param \\SelectQuery $query\n   *   The query object.\n   *\n   * @throws BadRequestException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function queryForListFilter(\\SelectQuery $query) {\n    foreach ($this->parseRequestForListFilter() as $filter) {\n      /* @var ResourceFieldDbColumnInterface $filter_field */\n      if (!$filter_field = $this->fieldDefinitions->get($filter['public_field'])) {\n        continue;\n      }\n      $column_name = $filter_field->getColumnForQuery();\n      if (in_array(strtoupper($filter['operator'][0]), array('IN', 'NOT IN', 'BETWEEN'))) {\n        $query->condition($column_name, $filter['value'], $filter['operator'][0]);\n        continue;\n      }\n      $condition = db_condition($filter['conjunction']);\n      for ($index = 0; $index < count($filter['value']); $index++) {\n        $condition->condition($column_name, $filter['value'][$index], $filter['operator'][$index]);\n      }\n      $query->condition($condition);\n    }\n  }\n\n  /**\n   * Set correct page (i.e. range) for the query for list.\n   *\n   * Determine the page that should be seen. Page 1, is actually offset 0 in the\n   * query range.\n   *\n   * @param \\SelectQuery $query\n   *   The query object.\n   *\n   * @throws BadRequestException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function queryForListPagination(\\SelectQuery $query) {\n    list($range, $offset) = $this->parseRequestForListPagination();\n    $query->range($range, $offset);\n  }\n\n  /**\n   * Get a basic query object.\n   *\n   * @return \\SelectQuery\n   *   A new SelectQuery object for this connection.\n   */\n  protected function getQuery() {\n    $table = $this->getTableName();\n    return db_select($table)->fields($table);\n  }\n\n  /**\n   * Given an array of string ID's return a single column.\n   *\n   * Strings are divided by the delimiter self::COLUMN_IDS_SEPARATOR.\n   *\n   * @param array $identifiers\n   *   An array of object IDs.\n   * @param int $column\n   *   0-N Zero indexed\n   *\n   * @return array\n   *   Returns an array at index $column\n   */\n  protected function getColumnFromIds(array $identifiers, $column = 0) {\n    // Get a single column.\n    $get_part = function($identifier) use ($column) {\n      $parts = explode(static::COLUMN_IDS_SEPARATOR, $identifier);\n      if (!isset($parts[$column])) {\n        throw new ServerConfigurationException('Invalid ID provided.');\n      }\n      return $parts[$column];\n    };\n    return array_map($get_part, $identifiers);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function initDataInterpreter($identifier) {\n    return new DataInterpreterArray($this->getAccount(), new ArrayWrapper((array) $identifier));\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderDbQueryInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderDbQueryInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\ninterface DataProviderDbQueryInterface extends DataProviderInterface {\n\n  /**\n   * Get the name of the table to query.\n   *\n   * @return string\n   *   The name of the table to query.\n   */\n  public function getTableName();\n\n  /**\n   * Set the name of the table to query.\n   *\n   * @param string $table_name\n   *   The name of the table to query.\n   */\n  public function setTableName($table_name);\n\n  /**\n   * Gets the primary field.\n   *\n   * @return string\n   *   The field name.\n   */\n  public function getPrimary();\n\n  /**\n   * Sets the primary field.\n   *\n   * @param string $primary\n   *   The field name.\n   */\n  public function setPrimary($primary);\n\n  /**\n   * Checks if the current field is the primary field.\n   *\n   * @param string $field_name\n   *   The column name to check.\n   *\n   * @return bool\n   *   TRUE if it is the primary field, FALSE otherwise.\n   */\n  public function isPrimaryField($field_name);\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderDecorator.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderDecorator.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\n\nabstract class DataProviderDecorator implements DataProviderInterface {\n\n  /**\n   * Decorated provider.\n   *\n   * @var DataProviderInterface\n   */\n  protected $decorated;\n\n  /**\n   * Contstructs a DataProviderDecorator class.\n   *\n   * @param DataProviderInterface $decorated\n   *   The decorated data provider.\n   */\n  public function __construct(DataProviderInterface $decorated) {\n    $this->decorated = $decorated;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRange() {\n    return $this->decorated->getRange();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRange($range) {\n    $this->decorated->setRange($range);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount() {\n    return $this->decorated->getAccount();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->decorated->setAccount($account);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getLangCode() {\n    return $this->decorated->getLangCode();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setLangCode($langcode) {\n    $this->decorated->setLangCode($langcode);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getOptions() {\n    return $this->decorated->getOptions();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addOptions(array $options) {\n    $this->decorated->addOptions($options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheFragments($identifier) {\n    $this->decorated->getCacheFragments($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function canonicalPath($path) {\n    return $this->decorated->canonicalPath($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function methodAccess(ResourceFieldInterface $resource_field) {\n    return $this->decorated->methodAccess($resource_field);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setOptions(array $options) {\n    $this->decorated->setOptions($options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    return $this->decorated->getIndexIds();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index() {\n    return $this->decorated->index();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return $this->decorated->count();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    return $this->decorated->create($object);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    return $this->decorated->view($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    return $this->decorated->viewMultiple($identifiers);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    return $this->decorated->update($identifier, $object, $replace);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    $this->decorated->remove($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function discover($path = NULL) {\n    return $this->decorated->discover($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isNestedField($field_name) {\n    return DataProvider::isNestedField($field_name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function processFilterInput($filter, $public_field) {\n    return DataProvider::processFilterInput($filter, $public_field);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResourcePath($resource_path) {\n    $this->decorated->setResourcePath($resource_path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourcePath() {\n    return $this->decorated->getResourcePath();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMetadata() {\n    return $this->decorated->getMetadata();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderEntity.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntity.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Exception\\ForbiddenException;\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityAlterableInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterEMW;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntity;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\Resource;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Util\\ExplorableDecoratorInterface;\nuse Drupal\\restful\\Util\\RelationalFilter;\nuse Drupal\\restful\\Util\\RelationalFilterInterface;\nuse Drupal\\entity_validator\\ValidatorPluginManager;\n\n/**\n * Class DataProviderEntity.\n *\n * @package Drupal\\restful\\Plugin\\resource\\DataProvider\n */\nclass DataProviderEntity extends DataProvider implements DataProviderEntityInterface {\n\n  /**\n   * The entity type.\n   *\n   * @var string\n   */\n  protected $entityType;\n\n  /**\n   * The entity bundles.\n   *\n   * @var array\n   */\n  protected $bundles = array();\n\n  /**\n   * The entity field query class.\n   *\n   * @var string\n   */\n  protected $EFQClass = '\\Drupal\\restful\\Util\\EntityFieldQuery';\n\n  /**\n   * Constructor.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   * @param ResourceFieldCollectionInterface $field_definitions\n   *   The field definitions.\n   * @param object $account\n   *   The account object.\n   * @param string $plugin_id\n   *   The resource ID.\n   * @param string $resource_path\n   *   The resource path.\n   * @param array $options\n   *   The plugin definition options for the data provider.\n   * @param string $langcode\n   *   The entity language code.\n   *\n   * @throws InternalServerErrorException\n   *   If there is no entity type.\n   * @throws ServerConfigurationException\n   *   If the field mappings are not for entities.\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path, array $options, $langcode = NULL) {\n    parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);\n    if (empty($options['entityType'])) {\n      // Entity type is mandatory.\n      throw new InternalServerErrorException('The entity type was not provided.');\n    }\n    $this->entityType = $options['entityType'];\n\n    $options += array('bundles' => array());\n    if ($options['bundles']) {\n      $this->bundles = $options['bundles'];\n    }\n    elseif ($options['bundles'] !== FALSE) {\n      // If no bundles are passed, then assume all the bundles of the entity\n      // type.\n      $entity_info = entity_get_info($this->entityType);\n      $this->bundles = !empty($entity_info['bundles']) ? array_keys($entity_info['bundles']) : $entity_info['type'];\n    }\n\n    if (isset($options['EFQClass'])) {\n      $this->EFQClass = $options['EFQClass'];\n    }\n\n    $this->setResourcePath($resource_path);\n    if (empty($this->options['urlParams'])) {\n      $this->options['urlParams'] = array(\n        'filter' => TRUE,\n        'sort' => TRUE,\n        'fields' => TRUE,\n        'loadByFieldName' => TRUE,\n      );\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheFragments($identifier) {\n    if (is_array($identifier)) {\n      // Like in https://example.org/api/articles/1,2,3.\n      $identifier = implode(ResourceInterface::IDS_SEPARATOR, $identifier);\n    }\n    $fragments = new ArrayCollection(array(\n      'resource' => CacheDecoratedResource::serializeKeyValue($this->pluginId, $this->canonicalPath($identifier)),\n      'entity' => CacheDecoratedResource::serializeKeyValue($this->entityType, $this->getEntityIdByFieldId($identifier)),\n    ));\n    $options = $this->getOptions();\n    switch ($options['renderCache']['granularity']) {\n      case DRUPAL_CACHE_PER_USER:\n        if ($uid = $this->getAccount()->uid) {\n          $fragments->set('user_id', (int) $uid);\n        }\n        break;\n      case DRUPAL_CACHE_PER_ROLE:\n        $fragments->set('user_role', implode(',', $this->getAccount()->roles));\n        break;\n    }\n    return $fragments;\n  }\n\n  /**\n   * Defines default sort fields if none are provided via the request URL.\n   *\n   * @return array\n   *   Array keyed by the public field name, and the order ('ASC' or 'DESC') as\n   *   value.\n   */\n  protected function defaultSortInfo() {\n    return empty($this->options['sort']) ? array('id' => 'ASC') : $this->options['sort'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    $result = $this\n      ->getQueryForList()\n      ->execute();\n\n    if (empty($result[$this->entityType])) {\n      return array();\n    }\n\n    $entity_ids = array_keys($result[$this->entityType]);\n    if (empty($this->options['idField'])) {\n      return $entity_ids;\n    }\n\n    // Get the list of IDs.\n    $resource_field = $this->fieldDefinitions->get($this->options['idField']);\n    $ids = array();\n    foreach ($entity_ids as $entity_id) {\n      $interpreter = new DataInterpreterEMW($this->getAccount(), new \\EntityDrupalWrapper($this->entityType, $entity_id));\n      $ids[] = $resource_field->value($interpreter);\n    }\n\n    return $ids;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    $query = $this->getQueryCount();\n    return intval($query->execute());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    $this->validateBody($object);\n    $entity_info = $this->getEntityInfo();\n    $bundle_key = $entity_info['entity keys']['bundle'];\n    // TODO: figure out how to derive the bundle when posting to a resource with\n    // multiple bundles.\n    $bundle = reset($this->bundles);\n    $values = $bundle_key ? array($bundle_key => $bundle) : array();\n\n    $entity = entity_create($this->entityType, $values);\n\n    if ($this->checkEntityAccess('create', $this->entityType, $entity) === FALSE) {\n      // User does not have access to create entity.\n      throw new ForbiddenException('You do not have access to create a new resource.');\n    }\n\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper($this->entityType, $entity);\n\n    $this->setPropertyValues($wrapper, $object, TRUE);\n\n    // The access calls use the request method. Fake the view to be a GET.\n    $old_request = $this->getRequest();\n    $this->getRequest()->setMethod(RequestInterface::METHOD_GET);\n    $identifier = empty($this->options['idField'])\n      ? $wrapper->getIdentifier()\n      : $wrapper->get($this->options['idField'])->value();\n    $output = array($this->view($identifier));\n    // Put the original request back to a POST.\n    $this->request = $old_request;\n\n    return $output;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    $entity_id = $this->getEntityIdByFieldId($identifier);\n\n    if (!$this->isValidEntity('view', $entity_id)) {\n      throw new InaccessibleRecordException(sprintf('The current user cannot access entity \"%s\".', $entity_id));\n    }\n    $field_collection = $this->initResourceFieldCollection($identifier);\n    // Defer sparse fieldsets to the formatter. That way we can minimize cache\n    // fragmentation because we have a unique cache record for all the sparse\n    // fieldsets combinations.\n    // When caching is enabled and we get a cache MISS we want to generate\n    // output for the cache entry for the whole entity. That way we can use that\n    // cache record independently of the sparse fieldset.\n    // On the other hand, if cache is not enabled we don't want to output for\n    // the whole entity, only the bits that we are going to need. For\n    // performance reasons.\n    $input = $this->getRequest()->getParsedInput();\n    $limit_fields = !empty($input['fields']) ? explode(',', $input['fields']) : array();\n    $field_collection->setLimitFields($limit_fields);\n\n    foreach ($this->fieldDefinitions as $resource_field) {\n      // Create an empty field collection and populate it with the appropriate\n      // resource fields.\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityInterface $resource_field */\n\n      if (!$this->methodAccess($resource_field) || !$resource_field->access('view', $field_collection->getInterpreter())) {\n        // The field does not apply to the current method or has denied access.\n        continue;\n      }\n\n      $field_collection->set($resource_field->id(), $resource_field);\n    }\n\n    return $field_collection;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    $return = array();\n    // If no IDs were requested, we should not throw an exception in case an\n    // entity is un-accessible by the user.\n    foreach ($identifiers as $identifier) {\n      try {\n        $row = $this->view($identifier);\n      }\n      catch (InaccessibleRecordException $e) {\n        $row = NULL;\n      }\n      $return[] = $row;\n    }\n\n    return array_values(array_filter($return));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    $this->validateBody($object);\n    $entity_id = $this->getEntityIdByFieldId($identifier);\n    $this->isValidEntity('update', $entity_id);\n\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper($this->entityType, $entity_id);\n\n    $this->setPropertyValues($wrapper, $object, $replace);\n\n    // Set the HTTP headers.\n    $this->setHttpHeader('Status', 201);\n\n    if (!empty($wrapper->url) && $url = $wrapper->url->value()) {\n      $this->setHttpHeader('Location', $url);\n    }\n\n    // The access calls use the request method. Fake the view to be a GET.\n    $old_request = $this->getRequest();\n    $this->getRequest()->setMethod(RequestInterface::METHOD_GET);\n    $output = array($this->view($identifier));\n    // Put the original request back to a PUT/PATCH.\n    $this->request = $old_request;\n\n    return $output;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    $identifier = $this->getEntityIdByFieldId($identifier);\n    $this->isValidEntity('delete', $identifier);\n\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper($this->entityType, $identifier);\n    $wrapper->delete();\n\n    // Set the HTTP headers.\n    $this->setHttpHeader('Status', 204);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function canonicalPath($path) {\n    $ids = explode(Resource::IDS_SEPARATOR, $path);\n    $canonical_ids = array_map(array($this, 'getEntityIdByFieldId'), $ids);\n    return implode(Resource::IDS_SEPARATOR, $canonical_ids);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function entityPreSave(\\EntityDrupalWrapper $wrapper) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public function entityValidate(\\EntityDrupalWrapper $wrapper) {\n    if (!module_exists('entity_validator')) {\n      // Entity validator doesn't exist.\n      return;\n    }\n\n    try {\n      $validator_handler = ValidatorPluginManager::EntityValidator($wrapper->type(), $wrapper->getBundle());\n    }\n    catch (PluginNotFoundException $e) {\n      // Entity validator handler doesn't exist for the entity.\n      return;\n    }\n\n    if ($validator_handler->validate($wrapper->value(), TRUE)) {\n      // Entity is valid.\n      return;\n    }\n\n    $errors = $validator_handler->getErrors(FALSE);\n\n    $map = array();\n    foreach ($this->fieldDefinitions as $resource_field_name => $resource_field) {\n      if (!$property = $resource_field->getProperty()) {\n        continue;\n      }\n\n      $public_name = $resource_field->getPublicName();\n      if (empty($errors[$public_name])) {\n        // Field validated.\n        continue;\n      }\n\n      $map[$public_name] = $resource_field_name;\n      $params['@fields'][] = $resource_field_name;\n    }\n\n    if (empty($params['@fields'])) {\n      // There was a validation error, but on non-public fields, so we need to\n      // throw an exception, but can't say on which fields it occurred.\n      throw new BadRequestException('Invalid value(s) sent with the request.');\n    }\n\n    $params['@fields'] = implode(',', $params['@fields']);\n    $exception = new BadRequestException(format_plural(count($map), 'Invalid value in field @fields.', 'Invalid values in fields @fields.', $params));\n    foreach ($errors as $property_name => $messages) {\n      if (empty($map[$property_name])) {\n        // Entity is not valid, but on a field not public.\n        continue;\n      }\n\n      $resource_field_name = $map[$property_name];\n\n      foreach ($messages as $message) {\n\n        $message['params']['@field'] = $resource_field_name;\n        $output = format_string($message['message'], $message['params']);\n\n        $exception->addFieldError($resource_field_name, $output);\n      }\n    }\n\n    // Throw the exception.\n    throw $exception;\n  }\n\n  /**\n   * Get the entity ID based on the ID provided in the request.\n   *\n   * As any field may be used as the ID, we convert it to the numeric internal\n   * ID of the entity\n   *\n   * @param mixed $id\n   *   The provided ID.\n   *\n   * @throws BadRequestException\n   * @throws UnprocessableEntityException\n   *\n   * @return int\n   *   The entity ID.\n   */\n  protected function getEntityIdByFieldId($id) {\n    $request = $this->getRequest();\n    $input = $request->getParsedInput();\n    $public_property_name = empty($input['loadByFieldName']) ? NULL : $input['loadByFieldName'];\n    $public_property_name = $public_property_name ?: (empty($this->options['idField']) ? NULL : $this->options['idField']);\n    if (!$public_property_name) {\n      // The regular entity ID was provided.\n      return $id;\n    }\n    // We need to get the internal field/property from the public name.\n    if ((!$public_field_info = $this->fieldDefinitions->get($public_property_name)) || !$public_field_info->getProperty()) {\n      throw new BadRequestException(format_string('Cannot load an entity using the field \"@name\"', array(\n        '@name' => $public_property_name,\n      )));\n    }\n    $query = $this->getEntityFieldQuery();\n    $query->range(0, 1);\n    // Find out if the provided ID is a Drupal field or an entity property.\n    $property = $public_field_info->getProperty();\n    /* @var ResourceFieldEntity $public_field_info */\n    if (ResourceFieldEntity::propertyIsField($property)) {\n      $query->fieldCondition($property, $public_field_info->getColumn(), $id);\n    }\n    else {\n      $query->propertyCondition($property, $id);\n    }\n\n    // Execute the query and gather the results.\n    $result = $query->execute();\n    if (empty($result[$this->entityType])) {\n      throw new UnprocessableEntityException(format_string('The entity ID @id by @name cannot be loaded.', array(\n        '@id' => $id,\n        '@name' => $public_property_name,\n      )));\n    }\n\n    // There is nothing that guarantees that there is only one result, since\n    // this is user input data. Return the first ID.\n    $entity_id = key($result[$this->entityType]);\n\n    return $entity_id;\n  }\n\n  /**\n   * Initialize an EntityFieldQuery (or extending class).\n   *\n   * @return \\EntityFieldQuery\n   *   The initialized query with the basics filled in.\n   */\n  protected function getEntityFieldQuery() {\n    $query = $this->EFQObject();\n    $entity_type = $this->entityType;\n    $query->entityCondition('entity_type', $entity_type);\n    $entity_info = $this->getEntityInfo();\n    if (!empty($this->bundles) && $entity_info['entity keys']['bundle']) {\n      $query->entityCondition('bundle', $this->bundles, 'IN');\n    }\n    return $query;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function EFQObject() {\n    $efq_class = $this->EFQClass;\n    return new $efq_class();\n  }\n\n  /**\n   * Get the entity info for the current entity the endpoint handling.\n   *\n   * @param string $type\n   *   Optional. The entity type.\n   *\n   * @return array\n   *   The entity info.\n   *\n   * @see entity_get_info().\n   */\n  protected function getEntityInfo($type = NULL) {\n    return entity_get_info($type ? $type : $this->entityType);\n  }\n\n  /**\n   * Prepare a query for RestfulEntityBase::getList().\n   *\n   * @return \\Drupal\\restful\\Util\\EntityFieldQuery\n   *   The EntityFieldQuery object.\n   */\n  protected function getQueryForList() {\n    $query = $this->getEntityFieldQuery();\n\n    // If we are trying to filter or sort on a computed field, just ignore it\n    // and log an exception.\n    try {\n      $this->queryForListSort($query);\n    }\n    catch (BadRequestException $e) {\n      watchdog_exception('restful', $e);\n    }\n    try {\n      $this->queryForListFilter($query);\n    }\n    catch (BadRequestException $e) {\n      watchdog_exception('restful', $e);\n    }\n\n    $this->queryForListPagination($query);\n    $this->addExtraInfoToQuery($query);\n\n    return $query;\n  }\n\n  /**\n   * Prepare a query for RestfulEntityBase::count().\n   *\n   * @return \\EntityFieldQuery\n   *   The EntityFieldQuery object.\n   */\n  protected function getQueryCount() {\n    $query = $this->getEntityFieldQuery();\n\n    // If we are trying to filter or sort on a computed field, just ignore it\n    // and log an exception.\n    try {\n      $this->queryForListSort($query);\n    }\n    catch (BadRequestException $e) {\n      watchdog_exception('restful', $e);\n    }\n    try {\n      $this->queryForListFilter($query);\n    }\n    catch (BadRequestException $e) {\n      watchdog_exception('restful', $e);\n    }\n\n    $this->addExtraInfoToQuery($query);\n\n    return $query->count();\n  }\n\n  /**\n   * Adds query tags and metadata to the EntityFieldQuery.\n   *\n   * @param \\EntityFieldQuery $query\n   *   The query to enhance.\n   */\n  protected function addExtraInfoToQuery($query) {\n    parent::addExtraInfoToQuery($query);\n    // The only time you need to add the access tags to a EFQ is when you don't\n    // have fieldConditions.\n    if (empty($query->fieldConditions) && empty($query->order)) {\n      // Add a generic entity access tag to the query.\n      $query->addTag($this->entityType . '_access');\n    }\n    $query->addMetaData('restful_data_provider', $this);\n  }\n\n  /**\n   * Sort the query for list.\n   *\n   * @param \\EntityFieldQuery $query\n   *   The query object.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\EntityFieldQueryException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function queryForListSort(\\EntityFieldQuery $query) {\n    $resource_fields = $this->fieldDefinitions;\n\n    // Get the sorting options from the request object.\n    $sorts = $this->parseRequestForListSort();\n\n    $sorts = $sorts ? $sorts : $this->defaultSortInfo();\n\n    foreach ($sorts as $public_field_name => $direction) {\n      // Determine if sorting is by field or property.\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityInterface $resource_field */\n      if (!$resource_field = $resource_fields->get($public_field_name)) {\n        return;\n      }\n      $sort = array(\n        'public_field' => $public_field_name,\n        'direction' => $direction,\n        'resource_id' => $this->pluginId,\n      );\n      $sort = $this->alterSortQuery($sort, $query);\n      if (!empty($sort['processed'])) {\n        // If the sort was already processed by the alter filters, continue.\n        continue;\n      }\n      if (!$property_name = $resource_field->getProperty()) {\n        if (!$resource_field instanceof ResourceFieldEntityAlterableInterface) {\n          throw new BadRequestException('The current sort selection does not map to any entity property or Field API field.');\n        }\n        // If there was no property but the resource field was sortable, do\n        // not add the default field filtering.\n        // TODO: This is a workaround. The filtering logic should live in the resource field class.\n        return;\n      }\n      if (ResourceFieldEntity::propertyIsField($property_name)) {\n        $query->fieldOrderBy($property_name, $resource_field->getColumn(), $sort['direction']);\n      }\n      else {\n        $column = $this->getColumnFromProperty($property_name);\n        $query->propertyOrderBy($column, $sort['direction']);\n      }\n    }\n  }\n\n  /**\n   * Filter the query for list.\n   *\n   * @param \\EntityFieldQuery $query\n   *   The query object.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function queryForListFilter(\\EntityFieldQuery $query) {\n    $resource_fields = $this->fieldDefinitions;\n    $filters = $this->parseRequestForListFilter();\n    $this->validateFilters($filters);\n    foreach ($filters as $filter) {\n      // Determine if filtering is by field or property.\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityInterface $resource_field */\n      if (!$resource_field = $resource_fields->get($filter['public_field'])) {\n        if (!static::isNestedField($filter['public_field'])) {\n          // This is not a nested filter.\n          continue;\n        }\n        if (!empty($filter['target'])) {\n          // If we cannot find the field, it may be a nested filter. Check if\n          // the target of that is the current resource.\n          continue;\n        }\n        $this->addNestedFilter($filter, $query);\n        continue;\n      }\n\n      // Give the chance for other data providers to have a special handling for\n      // a given field.\n      $filter = $this->alterFilterQuery($filter, $query);\n      if (!empty($filter['processed'])) {\n        // If the filter was already processed by the alter filters, continue.\n        continue;\n      }\n      if (!$property_name = $resource_field->getProperty()) {\n        if (!$resource_field instanceof ResourceFieldEntityAlterableInterface) {\n          throw new BadRequestException(sprintf('The current filter \"%s\" selection does not map to any entity property or Field API field and has no custom filtering.', $filter['public_field']));\n        }\n        // If there was no property but the resource field was filterable, do\n        // not add the default field filtering.\n        // TODO: This is a workaround. The filtering logic should live in the resource field class.\n        return;\n      }\n      if (field_info_field($property_name)) {\n        if ($this::isMultipleValuOperator($filter['operator'][0])) {\n          $query->fieldCondition($property_name, $resource_field->getColumn(), $this->getReferencedIds($filter['value'], $resource_field), $filter['operator'][0]);\n          continue;\n        }\n        for ($index = 0; $index < count($filter['value']); $index++) {\n          // If referencing an entity by an alternate ID, retrieve the actual\n          // Drupal's entity ID using getReferencedId.\n          $query->fieldCondition($property_name, $resource_field->getColumn(), $this->getReferencedId($filter['value'][$index], $resource_field), $filter['operator'][$index]);\n        }\n      }\n      else {\n        $column = $this->getColumnFromProperty($property_name);\n        if ($this::isMultipleValuOperator($filter['operator'][0])) {\n          $query->propertyCondition($column, $this->getReferencedIds($filter['value'], $resource_field), $filter['operator'][0]);\n          continue;\n        }\n        for ($index = 0; $index < count($filter['value']); $index++) {\n          $query->propertyCondition($column, $this->getReferencedId($filter['value'][$index], $resource_field), $filter['operator'][$index]);\n        }\n      }\n    }\n  }\n\n  /**\n   * Placeholder method to alter the filters.\n   *\n   * If no further processing for the filter is needed (i.e. alterFilterQuery\n   * already added the query filters to $query), then set the 'processed' flag\n   * in $filter to TRUE. Otherwise normal filtering will be added on top,\n   * leading to unexpected results.\n   *\n   * @param array $filter\n   *   The parsed filter information.\n   * @param \\EntityFieldQuery $query\n   *   The EFQ to add the filter to.\n   *\n   * @return array\n   *   The modified $filter array.\n   */\n  protected function alterFilterQuery(array $filter, \\EntityFieldQuery $query) {\n    if (!$resource_field = $this->fieldDefinitions->get($filter['public_field'])) {\n      return $filter;\n    }\n    if (!$resource_field instanceof ResourceFieldEntityAlterableInterface) {\n      // Check if the resource can check on decorated instances.\n      if (!$resource_field instanceof ExplorableDecoratorInterface || !$resource_field->isInstanceOf(ResourceFieldEntityAlterableInterface::class)) {\n        return $filter;\n      }\n    }\n    return $resource_field->alterFilterEntityFieldQuery($filter, $query);\n  }\n\n  /**\n   * Placeholder method to alter the filters.\n   *\n   * If no further processing for the filter is needed (i.e. alterFilterQuery\n   * already added the query filters to $query), then set the 'processed' flag\n   * in $filter to TRUE. Otherwise normal filtering will be added on top,\n   * leading to unexpected results.\n   *\n   * @param array $sort\n   *   The sort array containing the keys:\n   *     - public_field: Contains the public property.\n   *     - direction: The sorting direction, either ASC or DESC.\n   *     - resource_id: The resource machine name.\n   * @param \\EntityFieldQuery $query\n   *   The EFQ to add the filter to.\n   *\n   * @return array\n   *   The modified $sort array.\n   */\n  protected function alterSortQuery(array $sort, \\EntityFieldQuery $query) {\n    if (!$resource_field = $this->fieldDefinitions->get($sort['public_field'])) {\n      return $sort;\n    }\n    if (!$resource_field instanceof ResourceFieldEntityAlterableInterface) {\n      // Check if the resource can check on decorated instances.\n      if (!$resource_field instanceof ExplorableDecoratorInterface || !$resource_field->isInstanceOf(ResourceFieldEntityAlterableInterface::class)) {\n        return $sort;\n      }\n    }\n    return $resource_field->alterSortEntityFieldQuery($sort, $query);\n  }\n\n  /**\n   * Checks if the operator accepts multiple values.\n   *\n   * @param $operator_name\n   *   The name of the operator.\n   *\n   * @return bool\n   *   TRUE if the operator can interpret multiple values. FALSE otherwise.\n   */\n  protected static function isMultipleValuOperator($operator_name) {\n    return in_array(strtoupper($operator_name), array('IN', 'NOT IN', 'BETWEEN'));\n  }\n\n  /**\n   * Validates the query parameters.\n   *\n   * @param array $filters\n   *   The parsed filters.\n   *\n   * @throws BadRequestException\n   *   When there is an invalid target for relational filters.\n   */\n  protected function validateFilters(array $filters) {\n    foreach ($filters as $filter) {\n      if (empty($filter['target'])) {\n        continue;\n      }\n      // If the target is not a part of the field, then raise an error.\n      $field_name_parts = explode('.', $filter['public_field']);\n      $target_parts = explode('.', $filter['target']);\n      foreach ($target_parts as $delta => $target_part) {\n        if ($target_part != $field_name_parts[$delta]) {\n          // There is a discrepancy between target and field name.\n          throw new BadRequestException(sprintf('The target \"%s\" should be a part of the field name \"%s\".', $filter['target'], $filter['public_field']));\n        }\n      }\n    }\n  }\n\n  /**\n   * Set correct page (i.e. range) for the query for list.\n   *\n   * Determine the page that should be seen. Page 1, is actually offset 0 in the\n   * query range.\n   *\n   * @param \\EntityFieldQuery $query\n   *   The query object.\n   *\n   * @throws BadRequestException\n   *\n   * @see \\RestfulEntityBase::getQueryForList\n   */\n  protected function queryForListPagination(\\EntityFieldQuery $query) {\n    list($offset, $range) = $this->parseRequestForListPagination();\n    $query->range($offset, $range);\n  }\n\n  /**\n   * Overrides DataProvider::isValidOperatorsForFilter().\n   */\n  protected static function isValidOperatorsForFilter(array $operators) {\n    $allowed_operators = array(\n      '=',\n      '>',\n      '<',\n      '>=',\n      '<=',\n      '<>',\n      '!=',\n      'BETWEEN',\n      'CONTAINS',\n      'IN',\n      'LIKE',\n      'NOT IN',\n      'STARTS_WITH',\n    );\n\n    foreach ($operators as $operator) {\n      if (!in_array($operator, $allowed_operators)) {\n        throw new BadRequestException(sprintf('Operator \"%s\" is not allowed for filtering on this resource. Allowed operators are: %s', $operator, implode(', ', $allowed_operators)));\n      }\n    }\n  }\n\n  /**\n   * Overrides DataProvider::isValidConjunctionForFilter().\n   */\n  protected static function isValidConjunctionForFilter($conjunction) {\n    $allowed_conjunctions = array(\n      'AND',\n    );\n\n    if (!in_array(strtoupper($conjunction), $allowed_conjunctions)) {\n      throw new BadRequestException(format_string('Conjunction \"@conjunction\" is not allowed for filtering on this resource. Allowed conjunctions are: !allowed', array(\n        '@conjunction' => $conjunction,\n        '!allowed' => implode(', ', $allowed_conjunctions),\n      )));\n    }\n  }\n\n  /**\n   * Get the DB column name from a property.\n   *\n   * The \"property\" defined in the public field is actually the property\n   * of the entity metadata wrapper. Sometimes that property can be a\n   * different name than the column in the DB. For example, for nodes the\n   * \"uid\" property is mapped in entity metadata wrapper as \"author\", so\n   * we make sure to get the real column name.\n   *\n   * @param string $property_name\n   *   The property name.\n   *\n   * @return string\n   *   The column name.\n   */\n  protected function getColumnFromProperty($property_name) {\n    $property_info = entity_get_property_info($this->entityType);\n    return $property_info['properties'][$property_name]['schema field'];\n  }\n\n  /**\n   * Determine if an entity is valid, and accessible.\n   *\n   * @param string $op\n   *   The operation to perform on the entity (view, update, delete).\n   * @param int $entity_id\n   *   The entity ID.\n   *\n   * @return bool\n   *   TRUE if entity is valid, and user can access it.\n   *\n   * @throws UnprocessableEntityException\n   * @throws InaccessibleRecordException\n   */\n  protected function isValidEntity($op, $entity_id) {\n    $entity_type = $this->entityType;\n\n    if (!ctype_digit((string) $entity_id) || !$entity = entity_load_single($entity_type, $entity_id)) {\n      // We need to check if the entity ID is numeric since if this is a uuid\n      // that starts by the number 4, and there is an entity with ID 4 that\n      // entity will be loaded incorrectly.\n      throw new UnprocessableEntityException(sprintf('The entity ID %s does not exist.', $entity_id));\n    }\n\n    list(,, $bundle) = entity_extract_ids($entity_type, $entity);\n\n    if (!empty($this->bundles) && !in_array($bundle, $this->bundles)) {\n      return FALSE;\n    }\n\n    if ($this->checkEntityAccess($op, $entity_type, $entity) === FALSE) {\n\n      if ($op == 'view' && !$this->getResourcePath()) {\n        // Just return FALSE, without an exception, for example when a list of\n        // entities is requested, and we don't want to fail all the list because\n        // of a single item without access.\n        // Add the inaccessible item to the metadata to fix the record count in\n        // the formatter.\n        $inaccessible_records = $this->getMetadata()->get('inaccessible_records');\n        $inaccessible_records[] = array(\n          'resource' => $this->pluginId,\n          'id' => $entity_id,\n        );\n        $this->getMetadata()->set('inaccessible_records', $inaccessible_records);\n\n        return FALSE;\n      }\n\n      // Entity was explicitly requested so we need to throw an exception.\n      throw new InaccessibleRecordException(sprintf('You do not have access to entity ID %s.', $entity_id));\n    }\n\n    return TRUE;\n  }\n\n  /**\n   * Check access to CRUD an entity.\n   *\n   * @param string $op\n   *   The operation. Allowed values are \"create\", \"update\" and \"delete\".\n   * @param string $entity_type\n   *   The entity type.\n   * @param object $entity\n   *   The entity object.\n   *\n   * @return bool\n   *   TRUE or FALSE based on the access. If no access is known about the entity\n   *   return NULL.\n   */\n  protected function checkEntityAccess($op, $entity_type, $entity) {\n    $account = $this->getAccount();\n    return entity_access($op, $entity_type, $entity, $account);\n  }\n\n  /**\n   * Set properties of the entity based on the request, and save the entity.\n   *\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The wrapped entity object, passed by reference.\n   * @param array $object\n   *   The keyed array of properties sent in the payload.\n   * @param bool $replace\n   *   Determine if properties that are missing from the request array should\n   *   be treated as NULL, or should be skipped. Defaults to FALSE, which will\n   *   set the fields to NULL.\n   *\n   * @throws BadRequestException\n   *   If the provided object is not valid.\n   */\n  protected function setPropertyValues(\\EntityDrupalWrapper $wrapper, $object, $replace = FALSE) {\n    if (!is_array($object)) {\n      throw new BadRequestException('Bad input data provided. Please, check your input and your Content-Type header.');\n    }\n    $save = FALSE;\n    $original_object = $object;\n    $interpreter = new DataInterpreterEMW($this->getAccount(), $wrapper);\n    // Keeps a list of the fields that have been set.\n    $processed_fields = array();\n\n    $field_definitions = clone $this->fieldDefinitions;\n    foreach ($field_definitions as $public_field_name => $resource_field) {\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityInterface $resource_field */\n\n      if (!$this->methodAccess($resource_field)) {\n        // Allow passing the value in the request.\n        unset($original_object[$public_field_name]);\n        continue;\n      }\n\n      $property_name = $resource_field->getProperty();\n      if ($resource_field->isComputed()) {\n        // We may have for example an entity with no label property, but with a\n        // label callback. In that case the $info['property'] won't exist, so\n        // we skip this field.\n        unset($original_object[$public_field_name]);\n        continue;\n      }\n\n      $entity_property_access = $this::checkPropertyAccess($resource_field, 'edit', $interpreter);\n      if (!array_key_exists($public_field_name, $object)) {\n        // No property to set in the request.\n        // Only set this to NULL if this property has not been set to a specific\n        // value by another public field (since 2 public fields can reference\n        // the same property).\n        if ($replace && $entity_property_access && !in_array($property_name, $processed_fields)) {\n          // We need to set the value to NULL.\n          $field_value = NULL;\n        }\n        else {\n          // Either we shouldn't set missing fields as NULL or access is denied\n          // for the current property, hence we skip.\n          continue;\n        }\n      }\n      else {\n        // Property is set in the request.\n        // Delegate modifications on the value of the field.\n        $field_value = $resource_field->preprocess($object[$public_field_name]);\n      }\n      $resource_field->set($field_value, $interpreter);\n      // We check the property access only after setting the values, as the\n      // access callback's response might change according to the field value.\n      $entity_property_access = $this::checkPropertyAccess($resource_field, 'edit', $interpreter);\n      if (!$entity_property_access) {\n        throw new BadRequestException(format_string('Property @name cannot be set.', array('@name' => $public_field_name)));\n      }\n\n      $processed_fields[] = $property_name;\n      unset($original_object[$public_field_name]);\n      $save = TRUE;\n    }\n\n    if (!$save) {\n      // No request was sent.\n      throw new BadRequestException('No values were sent with the request');\n    }\n\n    if ($original_object) {\n      // Request had illegal values.\n      $error_message = format_plural(count($original_object), 'Property @names is invalid.', 'Properties @names are invalid.', array('@names' => implode(', ', array_keys($original_object))));\n      throw new BadRequestException($error_message);\n    }\n\n    // Allow changing the entity just before it's saved. For example, setting\n    // the author of the node entity.\n    $this->entityPreSave($interpreter->getWrapper());\n\n    $this->entityValidate($interpreter->getWrapper());\n\n    $wrapper->save();\n  }\n\n  /**\n   * Validates the body payload object for entities.\n   *\n   * @param mixed $body\n   *   The parsed body.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *   For the empty body.\n   */\n  protected function validateBody($body) {\n    if (isset($body) && !is_array($body)) {\n      $message = sprintf('Incorrect object parsed: %s', print_r($body, TRUE));\n      throw new BadRequestException($message);\n    }\n  }\n\n  /**\n   * Checks if the data provider user has access to the property.\n   *\n   * @param \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface $resource_field\n   *   The field to check access on.\n   * @param string $op\n   *   The operation to be performed on the field.\n   * @param \\Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface $interpreter\n   *   The data interpreter.\n   *\n   * @return bool\n   *   TRUE if the user has access to the property.\n   */\n  protected static function checkPropertyAccess(ResourceFieldInterface $resource_field, $op, DataInterpreterInterface $interpreter) {\n    return $resource_field->access($op, $interpreter);\n  }\n\n  /**\n   * Get referenced ID.\n   *\n   * @param string $value\n   *   The provided value, it can be an ID or not.\n   * @param ResourceFieldInterface $resource_field\n   *   The resource field that points to another entity.\n   *\n   * @return string\n   *   If the field uses an alternate ID property, then the ID gets translated\n   *   to the original entity ID. If not, then the same provided ID is returned.\n   *\n   * @todo: Add testing to this functionality.\n   */\n  protected function getReferencedId($value, ResourceFieldInterface $resource_field) {\n    $field_definition = $resource_field->getDefinition();\n    if (empty($field_definition['referencedIdProperty'])) {\n      return $value;\n    }\n    // Get information about the the Drupal field to see what entity type we are\n    // dealing with.\n    $field_info = field_info_field($resource_field->getProperty());\n    // We support:\n    // - Entity Reference.\n    // - Taxonomy Term.\n    // - File & Image field.\n    // - uid property.\n    // - vid property.\n    // If you need to support other types, you can create a custom data provider\n    // that overrides this method.\n    $target_entity_type = NULL;\n    $bundles = array();\n    if (!$field_info) {\n      if ($resource_field->getProperty() == 'uid') {\n        // We make a special case for the user id.\n        $target_entity_type = 'user';\n      }\n      elseif ($resource_field->getProperty() == 'vid') {\n        // We make a special case for the vocabulary id.\n        $target_entity_type = 'taxonomy_vocabulary';\n      }\n    }\n    elseif (!empty($field_info['type']) && $field_info['type'] == 'entityreference') {\n      $target_entity_type = $field_info['settings']['target_type'];\n      $bundles = empty($field_info['settings']['handler_settings']['target_bundles']) ? array() : $field_info['settings']['handler_settings']['target_bundles'];\n    }\n    elseif (!empty($field_info['type']) && $field_info['type'] == 'file') {\n      $target_entity_type = 'file';\n    }\n    elseif (!empty($field_info['type']) && $field_info['type'] == 'taxonomy_term_reference') {\n      $target_entity_type = 'taxonomy_term';\n      // Narrow down with the vocabulary information. Very useful if there are\n      // multiple terms with the same name in different vocabularies.\n      foreach ($field_info['settings']['allowed_values'] as $allowed_value) {\n        $bundles[] = $allowed_value['vocabulary'];\n      }\n    }\n    if (empty($target_entity_type) && $resource_field instanceof ResourceFieldResourceInterface && ($resource_info = $resource_field->getResource())) {\n      $instance_id = sprintf('%s:%d.%d', $resource_info['name'], $resource_info['majorVersion'], $resource_info['minorVersion']);\n      try {\n        $handler = restful()->getResourceManager()->getPlugin($instance_id);\n        if ($handler instanceof ResourceEntity) {\n          $target_entity_type = $handler->getEntityType();\n          $bundles = $handler->getBundles();\n        }\n      }\n      catch (PluginNotFoundException $e) {\n        // Do nothing.\n      }\n    }\n    if (empty($target_entity_type)) {\n      return $value;\n    }\n\n    // Now we have the entity type and bundles to look for the entity based on\n    // the contents of the field or the entity property.\n    $query = $this->EFQObject();\n    $query->entityCondition('entity_type', $target_entity_type);\n    if (!empty($bundles)) {\n      // Narrow down for bundles.\n      $query->entityCondition('bundle', $bundles, 'IN');\n    }\n\n    // Check if the referencedIdProperty is a field or a property.\n    $id_property = $field_definition['referencedIdProperty'];\n    if (field_info_field($id_property)) {\n      $query->fieldCondition($id_property, $resource_field->getColumn(), $value);\n    }\n    else {\n      $query->propertyCondition($id_property, $value);\n    }\n    // Only one result is returned. This assumes the reference fields are unique\n    // for every entity.\n    $results = $query->range(0, 1)->execute();\n    if ($results[$target_entity_type]) {\n      return key($results[$target_entity_type]);\n    }\n    // If no entity could be found, fall back to the original value.\n    return $value;\n  }\n\n  /**\n   * Get reference IDs for multiple values.\n   *\n   * @param array $values\n   *   The provided values, they can be an IDs or not.\n   * @param ResourceFieldInterface $resource_field\n   *   The resource field that points to another entity.\n   *\n   * @return string\n   *   If the field uses an alternate ID property, then the ID gets translated\n   *   to the original entity ID. If not, then the same provided ID is returned.\n   *\n   * @see getReferencedId()\n   */\n  protected function getReferencedIds(array $values, ResourceFieldInterface $resource_field) {\n    $output = array();\n    foreach ($values as $value) {\n      $output[] = $this->getReferencedId($value, $resource_field);\n    }\n    return $output;\n  }\n\n  /**\n   * Add relational filters to EFQ.\n   *\n   * This is for situation like when you only want articles that have taxonomies\n   * that contain the word Drupal in their body field. This cannot be resolved\n   * via EFQ alone.\n   *\n   * @param array $filter\n   *   The filter.\n   * @param \\EntityFieldQuery $query\n   *   The query to alter.\n   */\n  protected function addNestedFilter(array $filter, \\EntityFieldQuery $query) {\n    $relational_filters = array();\n    foreach ($this->getFieldsInfoFromPublicName($filter['public_field']) as $field_info) {\n      $relational_filters[] = new RelationalFilter($field_info['name'], $field_info['type'], $field_info['column'], $field_info['entity_type'], $field_info['bundles'], $field_info['target_column']);\n    }\n    $query->addRelationship($filter + array('relational_filters' => $relational_filters));\n  }\n\n  /**\n   * Transform the nested public name into an array of Drupal field information.\n   *\n   * @param string $name\n   *   The dot separated public name.\n   *\n   * @throws ServerConfigurationException\n   *   When the required resource information is not available.\n   * @throws BadRequestException\n   *   When the nested field is invalid.\n   *\n   * @return array\n   *   An array of fields with name and type.\n   */\n  protected function getFieldsInfoFromPublicName($name) {\n    $public_field_names = explode('.', $name);\n    $last_public_field_name = array_pop($public_field_names);\n    $fields = array();\n\n    // The first field is in the current resource, but not the other ones.\n    $definitions = $this->fieldDefinitions;\n    foreach ($public_field_names as $index => $public_field_name) {\n      /* @var ResourceFieldEntity $resource_field */\n      $resource_field = $definitions->get($public_field_name);\n      // Get the resource for the field, so we can get information for the next\n      // iteration.\n      if (!$resource_field || !($resource = $resource_field->getResource())) {\n        throw new ServerConfigurationException(sprintf('The nested field %s cannot be accessed because %s has no resource associated to it.', $name, $public_field_name));\n      }\n      list($item, $definitions) = $this->getFieldsFromPublicNameItem($resource_field);\n      $fields[] = $item;\n    }\n    if (!$resource_field = $definitions->get($last_public_field_name)) {\n      throw new BadRequestException(sprintf('Invalid nested field provided %s', $last_public_field_name));\n    }\n    $property = $resource_field->getProperty();\n    $item = array(\n      'name' => $property,\n      'type' => ResourceFieldEntity::propertyIsField($property) ? RelationalFilterInterface::TYPE_FIELD : RelationalFilterInterface::TYPE_PROPERTY,\n      'entity_type' => NULL,\n      'bundles' => array(),\n      'target_column' => NULL,\n    );\n    $item['column'] = $item['type'] == RelationalFilterInterface::TYPE_FIELD ? $resource_field->getColumn() : NULL;\n    $fields[] = $item;\n\n    return $fields;\n  }\n\n  /**\n   * Get the (reference) field information for a single item.\n   *\n   * @param ResourceFieldInterface $resource_field\n   *   The resource field.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *\n   * @return array\n   *   An array containing the following keys:\n   *   - 'name': Drupal's internal field name. Ex: field_article_related\n   *   - 'type': Either a field or a property.\n   *   - 'entity_type': The entity type this field points to. Not populated if\n   *     the field is not a reference (for instance the destination field used\n   *     in the where clause).\n   *   - 'bundles': The allowed bundles for this field. Not populated if the\n   *     field is not a reference (for instance the destination field used in\n   *     the where clause).\n   */\n  protected function getFieldsFromPublicNameItem(ResourceFieldResourceInterface $resource_field) {\n    $property = $resource_field->getProperty();\n    $item = array(\n      'name' => $property,\n      'type' => ResourceFieldEntity::propertyIsField($property) ? RelationalFilterInterface::TYPE_FIELD : RelationalFilterInterface::TYPE_PROPERTY,\n      'entity_type' => NULL,\n      'bundles' => array(),\n      'target_column' => $resource_field->getTargetColumn(),\n    );\n    $item['column'] = $item['type'] == RelationalFilterInterface::TYPE_FIELD ? $resource_field->getColumn() : NULL;\n    /* @var ResourceEntity $resource */\n    $resource = $resource_field->getResourcePlugin();\n\n    // Variables for the next iteration.\n    $definitions = $resource->getFieldDefinitions();\n    $item['entity_type'] = $resource->getEntityType();\n    $item['bundles'] = $resource->getBundles();\n    return array($item, $definitions);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function initDataInterpreter($identifier) {\n    $id = $identifier;\n    $entity_id = $this->getEntityIdByFieldId($id);\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper($this->entityType, $entity_id);\n    $wrapper->language($this->getLangCode());\n    return new DataInterpreterEMW($this->getAccount(), $wrapper);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderEntityDecorator.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntityDecorator.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Exception\\BadRequestException;\n\nabstract class DataProviderEntityDecorator extends DataProviderDecorator implements DataProviderEntityInterface {\n\n  /**\n   * Decorated provider.\n   *\n   * @var DataProviderEntityInterface\n   */\n  protected $decorated;\n\n  /**\n   * Contstructs a DataProviderDecorator class.\n   *\n   * @param DataProviderEntityInterface $decorated\n   *   The decorated data provider.\n   */\n  public function __construct(DataProviderEntityInterface $decorated) {\n    // We are overriding the constructor only for the\n    // DataProviderEntityInterface type hinting.\n    parent::__construct($decorated);\n  }\n\n  /**\n   * Allow manipulating the entity before it is saved.\n   *\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The unsaved wrapped entity.\n   */\n  public function entityPreSave(\\EntityDrupalWrapper $wrapper) {\n    $this->decorated->entityPreSave($wrapper);\n  }\n\n  /**\n   * Validate an entity before it is saved.\n   *\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The wrapped entity.\n   *\n   * @throws BadRequestException\n   */\n  public function entityValidate(\\EntityDrupalWrapper $wrapper) {\n    $this->decorated->entityValidate($wrapper);\n  }\n\n  /**\n   * Gets a EFQ object.\n   *\n   * @return \\EntityFieldQuery\n   *   The object that inherits from \\EntityFieldQuery.\n   */\n  public function EFQObject() {\n    return $this->decorated->EFQObject();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderEntityInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntityInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Exception\\BadRequestException;\n\ninterface DataProviderEntityInterface extends DataProviderInterface {\n\n  /**\n   * Allow manipulating the entity before it is saved.\n   *\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The unsaved wrapped entity.\n   */\n  public function entityPreSave(\\EntityDrupalWrapper $wrapper);\n\n  /**\n   * Validate an entity before it is saved.\n   *\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The wrapped entity.\n   *\n   * @throws BadRequestException\n   */\n  public function entityValidate(\\EntityDrupalWrapper $wrapper);\n\n  /**\n   * Gets a EFQ object.\n   *\n   * @return \\EntityFieldQuery\n   *   The object that inherits from \\EntityFieldQuery.\n   */\n  public function EFQObject();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderFile.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderFile.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\ForbiddenException;\nuse Drupal\\restful\\Exception\\ServiceUnavailableException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\n\n/**\n * Class DataProviderFile.\n *\n * @package Drupal\\restful\\Plugin\\resource\\DataProvider\n */\nclass DataProviderFile extends DataProviderEntity implements DataProviderInterface {\n\n  /**\n   * Constructs a DataProviderFile object.\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path, array $options, $langcode = NULL) {\n    parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);\n\n    $file_options = empty($this->options['options']) ? array() : $this->options['options'];\n    $default_values = array(\n      'validators' => array(\n        'file_validate_extensions' => array(),\n        'file_validate_size' => array(),\n      ),\n      'scheme' => file_default_scheme(),\n      'replace' => FILE_EXISTS_RENAME,\n    );\n    $this->options['options'] = drupal_array_merge_deep($default_values, $file_options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    $files = $this->getRequest()->getFiles();\n    if (!$files) {\n      throw new BadRequestException('No files sent with the request.');\n    }\n\n    $ids = array();\n\n    foreach ($files as $file_info) {\n      // Populate the $_FILES the way file_save_upload() expects.\n      $name = $file_info['name'];\n      foreach ($file_info as $key => $value) {\n        $files['files'][$key][$name] = $value;\n      }\n\n      if (!$file = $this->fileSaveUpload($name, $files)) {\n        throw new BadRequestException('Unacceptable file sent with the request.');\n      }\n\n      // Required to be able to reference this file.\n      file_usage_add($file, 'restful', 'files', $file->fid);\n\n      $ids[] = $file->fid;\n    }\n\n    $return = array();\n    foreach ($ids as $id) {\n      // The access calls use the request method. Fake the view to be a GET.\n      $old_request = $this->getRequest();\n      $this->getRequest()->setMethod(RequestInterface::METHOD_GET);\n      try {\n        $return[] = array($this->view($id));\n      }\n      catch (ForbiddenException $e) {\n        // A forbidden element should not forbid access to the whole list.\n      }\n      // Put the original request back to a POST.\n      $this->request = $old_request;\n    }\n\n    return $return;\n  }\n\n  /**\n   * An adaptation of file_save_upload() that includes more verbose errors.\n   *\n   * @param string $source\n   *   A string specifying the filepath or URI of the uploaded file to save.\n   * @param array $files\n   *   Array containing information about the files.\n   *\n   * @return object\n   *   The saved file object.\n   *\n   * @throws BadRequestException\n   * @throws ServiceUnavailableException\n   *\n   * @see file_save_upload()\n   */\n  protected function fileSaveUpload($source, array $files) {\n    static $upload_cache;\n\n    $provider_options = $this->getOptions();\n    $options = $provider_options['options'];\n\n    $validators = empty($options['validators']) ? NULL : $options['validators'];\n    $destination = $options['scheme'] . \"://\";\n    $replace = empty($options['replace']) ? NULL : $options['replace'];\n\n    // Return cached objects without processing since the file will have\n    // already been processed and the paths in _FILES will be invalid.\n    if (isset($upload_cache[$source])) {\n      return $upload_cache[$source];\n    }\n\n    // Make sure there's an upload to process.\n    if (empty($files['files']['name'][$source])) {\n      return NULL;\n    }\n\n    $this->checkUploadErrors($source, $files);\n\n    // Begin building file object.\n    $file_array = array(\n      'uid' => $this->getAccount()->uid,\n      'status' => 0,\n      'filename' => trim(drupal_basename($files['files']['name'][$source]), '.'),\n      'uri' => $files['files']['tmp_name'][$source],\n      'filesize' => $files['files']['size'][$source],\n    );\n    $file_array['filemime'] = file_get_mimetype($file_array['filename']);\n\n    $file = (object) $file_array;\n\n    $extensions = '';\n    if (isset($validators['file_validate_extensions'])) {\n      if (isset($validators['file_validate_extensions'][0])) {\n        // Build the list of non-munged extensions if the caller provided them.\n        $extensions = $validators['file_validate_extensions'][0];\n      }\n      else {\n        // If 'file_validate_extensions' is set and the list is empty then the\n        // caller wants to allow any extension. In this case we have to remove\n        // the validator or else it will reject all extensions.\n        unset($validators['file_validate_extensions']);\n      }\n    }\n    else {\n      // No validator was provided, so add one using the default list.\n      // Build a default non-munged safe list for file_munge_filename().\n      $extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';\n      $validators['file_validate_extensions'] = array();\n      $validators['file_validate_extensions'][0] = $extensions;\n    }\n\n    if (!empty($extensions)) {\n      // Munge the filename to protect against possible malicious extension\n      // hiding within an unknown file type (ie: filename.html.foo).\n      $file->filename = file_munge_filename($file->filename, $extensions);\n    }\n\n    // Rename potentially executable files, to help prevent exploits (i.e. will\n    // rename filename.php.foo and filename.php to filename.php.foo.txt and\n    // filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads'\n    // evaluates to TRUE.\n    if (!variable_get('allow_insecure_uploads', 0) && preg_match('/\\.(php|pl|py|cgi|asp|js)(\\.|$)/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {\n      $file->filemime = 'text/plain';\n      $file->uri .= '.txt';\n      $file->filename .= '.txt';\n      // The .txt extension may not be in the allowed list of extensions. We\n      // have to add it here or else the file upload will fail.\n      if (!empty($extensions)) {\n        $validators['file_validate_extensions'][0] .= ' txt';\n\n        // Unlike file_save_upload() we don't need to let the user know that\n        // for security reasons, your upload has been renamed, since RESTful\n        // will return the file name in the response.\n      }\n    }\n\n    // If the destination is not provided, use the temporary directory.\n    if (empty($destination)) {\n      $destination = 'temporary://';\n    }\n\n    // Assert that the destination contains a valid stream.\n    $destination_scheme = file_uri_scheme($destination);\n    if (!$destination_scheme || !file_stream_wrapper_valid_scheme($destination_scheme)) {\n      $message = format_string('The file could not be uploaded, because the destination %destination is invalid.', array('%destination' => $destination));\n      throw new ServiceUnavailableException($message);\n    }\n\n    $file->source = $source;\n    // A URI may already have a trailing slash or look like \"public://\".\n    if (substr($destination, -1) != '/') {\n      $destination .= '/';\n    }\n    $file->destination = file_destination($destination . $file->filename, $replace);\n    // If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR\n    // and there's an existing file so we need to bail.\n    if ($file->destination === FALSE) {\n      $message = format_string('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', array('%source' => $source, '%directory' => $destination));\n      throw new ServiceUnavailableException($message);\n    }\n\n    // Add in our check of the the file name length.\n    $validators['file_validate_name_length'] = array();\n\n    // Call the validation functions specified by this function's caller.\n    $errors = file_validate($file, $validators);\n\n    // Check for errors.\n    if (!empty($errors)) {\n      $message = format_string('The specified file %name could not be uploaded.', array('%name' => $file->filename));\n      if (count($errors) > 1) {\n        $message .= theme('item_list', array('items' => $errors));\n      }\n      else {\n        $message .= ' ' . array_pop($errors);\n      }\n\n      throw new ServiceUnavailableException($message);\n    }\n\n    // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary\n    // directory. This overcomes open_basedir restrictions for future file\n    // operations.\n    $file->uri = $file->destination;\n    if (!$this::moveUploadedFile($files['files']['tmp_name'][$source], $file->uri)) {\n      watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->uri));\n      $message = 'File upload error. Could not move uploaded file.';\n      throw new ServiceUnavailableException($message);\n    }\n\n    // Set the permissions on the new file.\n    drupal_chmod($file->uri);\n\n    // If we are replacing an existing file re-use its database record.\n    if ($replace == FILE_EXISTS_REPLACE) {\n      $existing_files = file_load_multiple(array(), array('uri' => $file->uri));\n      if (count($existing_files)) {\n        $existing = reset($existing_files);\n        $file->fid = $existing->fid;\n      }\n    }\n\n    // Change the file status from temporary to permanent.\n    $file->status = FILE_STATUS_PERMANENT;\n\n    // If we made it this far it's safe to record this file in the database.\n    if ($file = file_save($file)) {\n      // Add file to the cache.\n      $upload_cache[$source] = $file;\n      return $file;\n    }\n\n    // Something went wrong, so throw a general exception.\n    throw new ServiceUnavailableException('Unknown error has occurred.');\n  }\n\n  /**\n   * Checks of there is an error with the file upload and throws an exception.\n   *\n   * @param string $source\n   *   The name of the uploaded file\n   * @param array $files\n   *   Array containing information about the files.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\ServiceUnavailableException\n   */\n  protected function checkUploadErrors($source, array $files) {\n    // Check for file upload errors and return FALSE if a lower level system\n    // error occurred. For a complete list of errors:\n    // See http://php.net/manual/features.file-upload.errors.php.\n    switch ($files['files']['error'][$source]) {\n      case UPLOAD_ERR_INI_SIZE:\n      case UPLOAD_ERR_FORM_SIZE:\n        $message = format_string('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array(\n          '%file' => $files['files']['name'][$source],\n          '%maxsize' => format_size(file_upload_max_size()),\n        ));\n        throw new BadRequestException($message);\n\n      case UPLOAD_ERR_PARTIAL:\n      case UPLOAD_ERR_NO_FILE:\n        $message = format_string('The file %file could not be saved, because the upload did not complete.', array('%file' => $files['files']['name'][$source]));\n        throw new BadRequestException($message);\n\n      case UPLOAD_ERR_OK:\n        // Final check that this is a valid upload, if it isn't, use the\n        // default error handler.\n        if ($this::isUploadedFile($files['files']['tmp_name'][$source])) {\n          break;\n        }\n\n      default:\n        // Unknown error.\n        $message = format_string('The file %file could not be saved. An unknown error has occurred.', array('%file' => $files['files']['name'][$source]));\n        throw new ServiceUnavailableException($message);\n    }\n  }\n\n  /**\n   * Helper function that checks if a file was uploaded via a POST request.\n   *\n   * @param string $filename\n   *   The name of the file.\n   *\n   * @return bool\n   *   TRUE if the file is uploaded. FALSE otherwise.\n   */\n  protected static function isUploadedFile($filename) {\n    return is_uploaded_file($filename);\n  }\n\n  /**\n   * Helper function that moves an uploaded file.\n   *\n   * @param string $filename\n   *   The path of the file to move.\n   * @param string $uri\n   *   The path where to move the file.\n   *\n   * @return bool\n   *   TRUE if the file was moved. FALSE otherwise.\n   */\n  protected static function moveUploadedFile($filename, $uri) {\n    return (bool) drupal_move_uploaded_file($filename, $uri);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\CrudInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\n\ninterface DataProviderInterface extends CrudInterface {\n\n  /**\n   * Return the discovery information for the given entity.\n   *\n   * @param string $path\n   *   The request path.\n   *\n   * @return array\n   *   An array of data for the thing being discovered.\n   */\n  public function discover($path = NULL);\n\n  /**\n   * Checks if the passed in string is a dot-nested field.\n   *\n   * @param string $field_name\n   *   The field name.\n   *\n   * @return bool\n   *   TRUE if the field is nested. FALSE otherwise.\n   */\n  public static function isNestedField($field_name);\n\n  /**\n   * Processes the input for a filter and adds the appropriate defaults.\n   *\n   * @param mixed $filter\n   *   The input value for the filter.\n   * @param string $public_field\n   *   The public name for the filter.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *\n   * @return array\n   *   The processed filter item with all of the defaults.\n   */\n  public static function processFilterInput($filter, $public_field);\n\n  /**\n   * Gets the range.\n   *\n   * @return int\n   *   The range\n   */\n  public function getRange();\n\n  /**\n   * Sets the range.\n   *\n   * @param int $range\n   *   The range\n   */\n  public function setRange($range);\n\n  /**\n   * Gets the authenticated account.\n   *\n   * @return object\n   *   The fully loaded user account.\n   */\n  public function getAccount();\n\n  /**\n   * Sets the authenticated account.\n   *\n   * @param object $account\n   *   The fully loaded user account.\n   */\n  public function setAccount($account);\n\n  /**\n   * Gets the request.\n   *\n   * @return RequestInterface\n   *   The request.\n   */\n  public function getRequest();\n\n  /**\n   * Sets the request.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   */\n  public function setRequest(RequestInterface $request);\n\n  /**\n   * Get the language code.\n   *\n   * @return string\n   *   The language code\n   */\n  public function getLangCode();\n\n  /**\n   * Sets the language code.\n   *\n   * @param string $langcode\n   *   The language code.\n   */\n  public function setLangCode($langcode);\n\n  /**\n   * Gets the data provider options.\n   *\n   * @return array\n   *   The array of options for the data provider.\n   */\n  public function getOptions();\n\n  /**\n   * Adds the options in the provided array to the data provider options.\n   *\n   * @param array $options\n   *   The array of options for the data provider.\n   */\n  public function addOptions(array $options);\n\n  /**\n   * Gets the entity context.\n   *\n   * @param mixed $identifier\n   *   The ID.\n   */\n  public function getCacheFragments($identifier);\n\n  /**\n   * Generates the canonical path for a given path.\n   *\n   * @param string $path\n   *   The aliased path.\n   *\n   * @return string\n   *   The canonical path.\n   */\n  public function canonicalPath($path);\n\n  /**\n   * Checks if the provided field can be used with the current method.\n   *\n   * @param ResourceFieldInterface $resource_field\n   *   The field.\n   *\n   * @return bool\n   *   TRUE if acces is granted. FALSE otherwise.\n   */\n  public function methodAccess(ResourceFieldInterface $resource_field);\n\n  /**\n   * Sets the options.\n   *\n   * @param array $options\n   *   The options to set.\n   */\n  public function setOptions(array $options);\n\n  /**\n   * Returns the ID to render for the current index GET request.\n   *\n   * @return array\n   *   Numeric array containing the identifiers to be sent to viewMultiple.\n   */\n  public function getIndexIds();\n\n  /**\n   * Set the resource path.\n   *\n   * @param string $resource_path\n   *   The resource path.\n   */\n  public function setResourcePath($resource_path);\n\n  /**\n   * Get the resource path.\n   *\n   * @return string\n   *   The resource path.\n   */\n  public function getResourcePath();\n\n  /**\n   * Returns the metadata collection.\n   *\n   * Data providers can add metadata reflecting the data gathering/setting\n   * process. This information is made available to formatters via the resource\n   * so extra metadata can be added to the output.\n   *\n   * @return \\Doctrine\\Common\\Collections\\ArrayCollection\n   *   The collection object.\n   */\n  public function getMetadata();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderNode.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderNode.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\n/**\n * Class DataProviderNode.\n *\n * @package Drupal\\restful\\Plugin\\resource\\DataProvider\n */\nclass DataProviderNode extends DataProviderEntity implements DataProviderInterface {\n\n  /**\n   * Overrides DataProviderEntity::getQueryForList().\n   *\n   * Expose only published nodes.\n   */\n  public function getQueryForList() {\n    $query = parent::getQueryForList();\n    $query->propertyCondition('status', NODE_PUBLISHED);\n    return $query;\n  }\n\n  /**\n   * Overrides DataProviderEntity::getQueryCount().\n   *\n   * Only count published nodes.\n   */\n  public function getQueryCount() {\n    $query = parent::getQueryCount();\n    $query->propertyCondition('status', NODE_PUBLISHED);\n    return $query;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function entityPreSave(\\EntityDrupalWrapper $wrapper) {\n    $node = $wrapper->value();\n    if (!empty($node->nid)) {\n      // Node is already saved.\n      return;\n    }\n    node_object_prepare($node);\n    $node->uid = $this->getAccount()->uid;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderNull.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderNull.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nclass DataProviderNull extends DataProvider implements DataProviderInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return 0;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n\n  public function view($identifier) {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function initDataInterpreter($identifier) {\n    return NULL;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderPlug.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderPlug.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\restful\\Exception\\NotFoundException;\nuse Drupal\\restful\\Exception\\NotImplementedException;\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Exception\\UnauthorizedException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterPlug;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\PluginWrapper;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\n\n/**\n * Class DataProviderPlug.\n *\n * @package Drupal\\restful\\Plugin\\resource\\DataProvider\n */\nclass DataProviderPlug extends DataProvider implements DataProviderInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path = NULL, array $options = array(), $langcode = NULL) {\n    parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);\n    if (empty($this->options['urlParams'])) {\n      $this->options['urlParams'] = array(\n        'filter' => TRUE,\n        'sort' => TRUE,\n        'fields' => TRUE,\n      );\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return count($this->getIndexIds());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    throw new NotImplementedException('You cannot create plugins through the API.');\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    $resource_field_collection = $this->initResourceFieldCollection($identifier);\n\n    $input = $this->getRequest()->getParsedInput();\n    $limit_fields = !empty($input['fields']) ? explode(',', $input['fields']) : array();\n\n    foreach ($this->fieldDefinitions as $resource_field_name => $resource_field) {\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface $resource_field */\n\n      if ($limit_fields && !in_array($resource_field_name, $limit_fields)) {\n        // Limit fields doesn't include this property.\n        continue;\n      }\n\n      if (!$this->methodAccess($resource_field) || !$resource_field->access('view', $resource_field_collection->getInterpreter())) {\n        // The field does not apply to the current method or has denied\n        // access.\n        continue;\n      }\n\n      $resource_field_collection->set($resource_field->id(), $resource_field);\n    }\n    return $resource_field_collection;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    $return = array();\n    foreach ($identifiers as $identifier) {\n      try {\n        $row = $this->view($identifier);\n      }\n      catch (InaccessibleRecordException $e) {\n        $row = NULL;\n      }\n      $return[] = $row;\n    }\n\n    return array_values(array_filter($return));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    // TODO: Document how to enable/disable resources using the API.\n    $disabled_plugins = variable_get('restful_disabled_plugins', array());\n    if ($object['enable']) {\n      $disabled_plugins[$identifier] = FALSE;\n    }\n    variable_set('restful_disabled_plugins', $disabled_plugins);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    // TODO: Document how to enable/disable resources using the API.\n    $disabled_plugins = variable_get('restful_disabled_plugins', array());\n    $disabled_plugins[$identifier] = TRUE;\n    variable_set('restful_disabled_plugins', $disabled_plugins);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    // Return all of the instance IDs.\n    $plugins = restful()\n      ->getResourceManager()\n      ->getPlugins();\n\n    $output = $plugins->getIterator()->getArrayCopy();\n\n    // Apply filters.\n    $output = $this->applyFilters($output);\n    $output = $this->applySort($output);\n    return array_keys($output);\n  }\n\n  /**\n   * Removes plugins from the list based on the request options.\n   *\n   * @param \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[] $plugins\n   *   The array of resource plugins keyed by instance ID.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[]\n   *   The same array minus the filtered plugins.\n   */\n  protected function applyFilters(array $plugins) {\n    $resource_manager = restful()->getResourceManager();\n    $filters = $this->parseRequestForListFilter();\n    // If the 'all' option is not present, then add a filters to retrieve only\n    // the last resource.\n    $input = $this->getRequest()->getParsedInput();\n    $all = !empty($input['all']);\n    // Apply the filter to the list of plugins.\n    foreach ($plugins as $instance_id => $plugin) {\n      if (!$all) {\n        // Remove the plugin if it's not the latest version.\n        $version = $plugin->getVersion();\n        list($last_major, $last_minor) = $resource_manager->getResourceLastVersion($plugin->getResourceMachineName());\n        if ($version['major'] != $last_major || $version['minor'] != $last_minor) {\n          // We don't add the major and minor versions to filters because we\n          // cannot depend on the presence of the versions as public fields.\n          unset($plugins[$instance_id]);\n          continue;\n        }\n      }\n      // If the discovery is turned off for the resource, unset it.\n      $definition = $plugin->getPluginDefinition();\n      if (!$definition['discoverable']) {\n        unset($plugins[$instance_id]);\n        continue;\n      }\n\n      // A filter on a result needs the ResourceFieldCollection representing the\n      // result to return.\n      $interpreter = new DataInterpreterPlug($this->getAccount(), new PluginWrapper($plugin));\n      $this->fieldDefinitions->setInterpreter($interpreter);\n      foreach ($filters as $filter) {\n        if (!$this->fieldDefinitions->evalFilter($filter)) {\n          unset($plugins[$instance_id]);\n        }\n      }\n    }\n    $this->fieldDefinitions->setInterpreter(NULL);\n    return $plugins;\n  }\n\n  /**\n   * Sorts plugins on the list based on the request options.\n   *\n   * @param \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[] $plugins\n   *   The array of resource plugins keyed by instance ID.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\ResourceInterface[]\n   *   The sorted array.\n   */\n  protected function applySort(array $plugins) {\n    if ($sorts = $this->parseRequestForListSort()) {\n      uasort($plugins, function ($plugin1, $plugin2) use ($sorts) {\n        $interpreter1 = new DataInterpreterPlug($this->getAccount(), new PluginWrapper($plugin1));\n        $interpreter2 = new DataInterpreterPlug($this->getAccount(), new PluginWrapper($plugin2));\n        foreach ($sorts as $key => $order) {\n          $property = $this->fieldDefinitions->get($key)->getProperty();\n          $value1 = $interpreter1->getWrapper()->get($property);\n          $value2 = $interpreter2->getWrapper()->get($property);\n          if ($value1 == $value2) {\n            continue;\n          }\n\n          return ($order == 'DESC' ? -1 : 1) * strcmp($value1, $value2);\n        }\n\n        return 0;\n      });\n    }\n    return $plugins;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function initDataInterpreter($identifier) {\n    $resource_manager = restful()->getResourceManager();\n    try {\n      $plugin = $resource_manager->getPlugin($identifier);\n    }\n    catch (UnauthorizedException $e) {\n      return NULL;\n    }\n    catch (PluginNotFoundException $e) {\n      throw new NotFoundException('Invalid URL path.');\n    }\n    // If the plugin is not discoverable throw an access denied exception.\n    $definition = $plugin->getPluginDefinition();\n    if (empty($definition['discoverable'])) {\n      throw new InaccessibleRecordException(sprintf('The plugin %s is not discoverable.', $plugin->getResourceName()));\n    }\n    return new DataInterpreterPlug($this->getAccount(), new PluginWrapper($plugin));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheFragments($identifier) {\n    // If we are trying to get the context for multiple ids, join them.\n    if (is_array($identifier)) {\n      $identifier = implode(',', $identifier);\n    }\n    $fragments = new ArrayCollection(array(\n      'resource' => $identifier,\n    ));\n    $options = $this->getOptions();\n    switch ($options['renderCache']['granularity']) {\n      case DRUPAL_CACHE_PER_USER:\n        if ($uid = $this->getAccount()->uid) {\n          $fragments->set('user_id', (int) $uid);\n        }\n        break;\n      case DRUPAL_CACHE_PER_ROLE:\n        $fragments->set('user_role', implode(',', $this->getAccount()->roles));\n        break;\n    }\n    return $fragments;\n  }\n\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderResource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderResource.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\ResourcePluginManager;\n\n/**\n * This data provider creates a resource and uses it to access the data.\n *\n * Class DataProviderResource\n * @package Drupal\\restful\\Plugin\\resource\\DataProvider\n */\nclass DataProviderResource extends DataProvider implements DataProviderResourceInterface {\n\n  /**\n   * The referenced resource.\n   *\n   * @var ResourceInterface\n   */\n  protected $resource;\n\n  /**\n   * The referenced data provider.\n   *\n   * @var DataProviderInterface\n   */\n  protected $referencedDataProvider;\n\n  /**\n   * Constructor.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   * @param ResourceFieldCollectionInterface $field_definitions\n   *   The field definitions.\n   * @param object $account\n   *   The authenticated account.\n   * @param string $plugin_id\n   *   The resource ID.\n   * @param string $resource_path\n   *   The resource path.\n   * @param array $options\n   *   The plugin options for the data provider.\n   * @param string $langcode\n   *   (Optional) The entity language code.\n   * @param ResourceInterface $resource\n   *   The referenced resource.\n   */\n  public function __construct(RequestInterface $request, ResourceFieldCollectionInterface $field_definitions, $account, $plugin_id, $resource_path, array $options, $langcode = NULL, ResourceInterface $resource = NULL) {\n    $resource->setRequest($request);\n    $this->resource = $resource;\n    $this->referencedDataProvider = $resource->getDataProvider();\n    parent::__construct($request, $field_definitions, $account, $plugin_id, $resource_path, $options, $langcode);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function init(RequestInterface $request, $resource_name, array $version, $resource_path = NULL) {\n    /* @var ResourceInterface $resource */\n    $instance_id = $resource_name . PluginBase::DERIVATIVE_SEPARATOR . $version[0] . '.' . $version[1];\n    $resource = restful()\n      ->getResourceManager()\n      ->getPluginCopy($instance_id, Request::create('', array(), RequestInterface::METHOD_GET));\n    $plugin_definition = $resource->getPluginDefinition();\n    $resource->setPath($resource_path);\n    return new static($request, $resource->getFieldDefinitions(), $resource->getAccount(), $resource->getPluginId(), $resource->getPath(), $plugin_definition['dataProvider'], static::getLanguage(), $resource);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index() {\n    return $this->referencedDataProvider->index();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIndexIds() {\n    return $this->referencedDataProvider->getIndexIds();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($object) {\n    return $this->referencedDataProvider->create($object);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($identifier) {\n    return $this->referencedDataProvider->view($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function viewMultiple(array $identifiers) {\n    return $this->referencedDataProvider->viewMultiple($identifiers);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($identifier, $object, $replace = FALSE) {\n    return $this->referencedDataProvider->update($identifier, $object, $replace);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($identifier) {\n    $this->referencedDataProvider->remove($identifier);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function merge($identifier, $object) {\n    if (!$identifier) {\n      return $this->referencedDataProvider->create($object);\n    }\n    $replace = ($method = $this->getRequest()->getMethod()) ? $method == RequestInterface::METHOD_PUT : FALSE;\n    return $this->referencedDataProvider->update($identifier, $object, $replace);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return $this->referencedDataProvider->count();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function initDataInterpreter($identifier) {\n    return NULL;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderResourceInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderResourceInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Http\\RequestInterface;\n\ninterface DataProviderResourceInterface extends DataProviderInterface {\n\n  /**\n   * Creates a new DataProviderResource object from the resource info.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   * @param string $resource_name\n   *   The resource name.\n   * @param array $version\n   *   The first position is the major version, the second is the minor version.\n   *\n   * @return DataProviderResourceInterface\n   *   The data provider.\n   */\n  public static function init(RequestInterface $request, $resource_name, array $version);\n\n  /**\n   * Create or update an item based on the payload.\n   *\n   * @param mixed $identifier\n   *   The resource item identifier.\n   * @param mixed $object\n   *   The payload.\n   *\n   * @return mixed\n   *   The identifier of the created or updated resource item.\n   */\n  public function merge($identifier, $object);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/DataProvider/DataProviderTaxonomyTerm.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntity.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\DataProvider;\n\nclass DataProviderTaxonomyTerm extends DataProviderEntity implements DataProviderEntityInterface {\n\n\n  /**\n   * Overrides DataProviderEntity::setPropertyValues().\n   *\n   * This class is created to override this method. This method is overridden to\n   * add the vocabulary ID based on the vocabulary machine name when creating a\n   * taxonomy term.\n   */\n  protected function setPropertyValues(\\EntityDrupalWrapper $wrapper, $object, $replace = FALSE) {\n    $term = $wrapper->value();\n    if (empty($term->vid)) {\n      $vocabulary = taxonomy_vocabulary_machine_name_load($term->vocabulary_machine_name);\n      $term->vid = $vocabulary->vid;\n    }\n\n    parent::setPropertyValues($wrapper, $object, $replace);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Decorators/CacheDecoratedResource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Decorators;\n\nuse Drupal\\restful\\Http\\HttpHeader;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\CacheDecoratedDataProvider;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController;\nuse Drupal\\restful\\RenderCache\\RenderCache;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\nclass CacheDecoratedResource extends ResourceDecoratorBase implements CacheDecoratedResourceInterface {\n\n  /**\n   * Separator string for cache fragment key value pairs.\n   */\n  const CACHE_PAIR_SEPARATOR = '#';\n\n  /**\n   * Cache controller object.\n   *\n   * @var \\DrupalCacheInterface\n   */\n  protected $cacheController;\n\n  /**\n   * The data provider.\n   *\n   * @var DataProviderInterface\n   */\n  protected $dataProvider;\n\n  /**\n   * Constructs a Drupal\\Component\\Plugin\\PluginBase object.\n   *\n   * @param ResourceInterface $subject\n   *   The decorated object.\n   * @param \\DrupalCacheInterface $cache_controller\n   *   Injected cache manager.\n   */\n  public function __construct(ResourceInterface $subject, \\DrupalCacheInterface $cache_controller = NULL) {\n    // TODO: Implement the ResourceManager factory to use the CacheDecoratedResource.\n    $this->subject = $subject;\n    $this->cacheController = $cache_controller ? $cache_controller : $this->newCacheObject();\n    $cache_info = $this->defaultCacheInfo();\n    $this->pluginDefinition['renderCache'] = $cache_info;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCacheController() {\n    return $this->cacheController;\n  }\n\n  /**\n   * Get the default cache object based on the plugin configuration.\n   *\n   * By default, this returns an instance of the DrupalDatabaseCache class.\n   * Classes implementing DrupalCacheInterface can register themselves both as a\n   * default implementation and for specific bins.\n   *\n   * @return \\DrupalCacheInterface\n   *   The cache object associated with the specified bin.\n   *\n   * @see \\DrupalCacheInterface\n   * @see _cache_get_object()\n   */\n  protected function newCacheObject() {\n    // We do not use drupal_static() here because we do not want to change the\n    // storage of a cache bin mid-request.\n    static $cache_object;\n    if (isset($cache_object)) {\n      // Return cached object.\n      return $cache_object;\n    }\n\n    $cache_info = $this->defaultCacheInfo();\n    $class_name = empty($cache_info['class']) ? NULL : $cache_info['class'];\n\n    // If there is no class name in the plugin definition, try to get it from\n    // the variables.\n    if (empty($class_name)) {\n      $class_name = variable_get('cache_class_' . $cache_info['bin']);\n    }\n    // If it is still empty, then default to drupal's default cache class.\n    if (empty($class_name)) {\n      $class_name = variable_get('cache_default_class', 'DrupalDatabaseCache');\n    }\n    $cache_object = new $class_name($cache_info['bin']);\n    return $cache_object;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function dataProviderFactory() {\n    if ($this->dataProvider && $this->dataProvider instanceof CacheDecoratedDataProvider) {\n      return $this->dataProvider;\n    }\n    // Get the data provider from the subject of the decorator.\n    $decorated_provider = $this->subject->dataProviderFactory();\n    $this->dataProvider = new CacheDecoratedDataProvider($decorated_provider, $this->getCacheController());\n    $plugin_definition = $this->getPluginDefinition();\n    $this->dataProvider->addOptions(array(\n      'renderCache' => $this->defaultCacheInfo(),\n      'resource' => array(\n        'version' => array(\n          'major' => $plugin_definition['majorVersion'],\n          'minor' => $plugin_definition['minorVersion'],\n        ),\n        'name' => $plugin_definition['resource'],\n      ),\n    ));\n    return $this->dataProvider;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPath() {\n    return $this->subject->getPath();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPath($path) {\n    $this->subject->setPath($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFieldDefinitions() {\n    return $this->subject->getFieldDefinitions();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDataProvider() {\n    if (isset($this->dataProvider)) {\n      return $this->dataProvider;\n    }\n    $this->dataProvider = $this->dataProviderFactory();\n    return $this->dataProvider;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setDataProvider(DataProviderInterface $data_provider = NULL) {\n    $this->dataProvider = $data_provider;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function process() {\n    $path = $this->getPath();\n\n    return ResourceManager::executeCallback($this->getControllerFromPath($path), array($path));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($path) {\n    // TODO: This is duplicating the code from Resource::view\n    $ids = explode(static::IDS_SEPARATOR, $path);\n\n    // REST requires a canonical URL for every resource.\n    $canonical_path = $this->getDataProvider()->canonicalPath($path);\n    $this\n      ->getRequest()\n      ->getHeaders()\n      ->add(HttpHeader::create('Link', $this->versionedUrl($canonical_path, array(), FALSE) . '; rel=\"canonical\"'));\n\n    // If there is only one ID then use 'view'. Else, use 'viewMultiple'. The\n    // difference between the two is that 'view' allows access denied\n    // exceptions.\n    if (count($ids) == 1) {\n      return array($this->getDataProvider()->view($ids[0]));\n    }\n    else {\n      return $this->getDataProvider()->viewMultiple($ids);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index($path) {\n    // TODO: This is duplicating the code from Resource::index\n    return $this->getDataProvider()->index();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($path) {\n    $this->invalidateResourceCache($path);\n    // Update according to the decorated.\n    return $this->subject->update($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function replace($path) {\n    $this->invalidateResourceCache($path);\n    // Update according to the decorated.\n    return $this->subject->replace($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($path) {\n    $this->invalidateResourceCache($path);\n    $this->subject->remove($path);\n  }\n\n  /**\n   * Gets the default cache info.\n   *\n   * @return array\n   *   The cache info.\n   */\n  protected function defaultCacheInfo() {\n    $plugin_definition = $this->getPluginDefinition();\n    $cache_info = empty($plugin_definition['renderCache']) ? array() : $plugin_definition['renderCache'];\n    $cache_info += array(\n      'render' => variable_get('restful_render_cache', FALSE),\n      'class' => NULL,\n      'bin' => RenderCache::CACHE_BIN,\n      'expire' => CACHE_PERMANENT,\n      'simpleInvalidate' => TRUE,\n      'granularity' => DRUPAL_CACHE_PER_USER,\n    );\n    return $cache_info;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceMachineName() {\n    return $this->subject->getResourceMachineName();\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * This is a decorated resource, get proxy the call until you reach the\n   * annotated resource.\n   */\n  public function getPluginDefinition() {\n    return $this->subject->getPluginDefinition();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function enable() {\n    $this->subject->enable();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function disable() {\n    $this->subject->disable();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isEnabled() {\n    return $this->subject->isEnabled();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function hasSimpleInvalidation() {\n    $data_provider = $this->getDataProvider();\n    $options = $data_provider->getOptions();\n    $cache_info = $options['renderCache'];\n    return !empty($cache_info['simpleInvalidate']);\n  }\n\n  /**\n   * Invalidates the resource cache for the given resource on the provided id.\n   *\n   * @param string $id\n   *   The id.\n   */\n  protected function invalidateResourceCache($id) {\n    // Invalidate the render cache for this resource.\n    $query = new \\EntityFieldQuery();\n    $canonical_id = $this->getDataProvider()->canonicalPath($id);\n    $query\n      ->entityCondition('entity_type', 'cache_fragment')\n      ->propertyCondition('type', 'resource')\n      ->propertyCondition('value', $this::serializeKeyValue($this->getResourceName(), $canonical_id));\n    foreach (CacheFragmentController::lookUpHashes($query) as $hash) {\n      $this->getCacheController()->clear($hash);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function serializeKeyValue($key, $value) {\n    return sprintf('%s%s%s', $key, static::CACHE_PAIR_SEPARATOR, $value);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Decorators/CacheDecoratedResourceInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResourceInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Decorators;\n\n\ninterface CacheDecoratedResourceInterface extends ResourceDecoratorInterface {\n  /**\n   * Generates a serialized key value pair.\n   *\n   * @param string $key\n   *   The key\n   * @param string $value\n   *   The value.\n   *\n   * @return string\n   *   The serialized value.\n   */\n  public static function serializeKeyValue($key, $value);\n\n\n  /**\n   * Getter for $cacheController.\n   *\n   * @return \\DrupalCacheInterface\n   *   The cache object.\n   */\n  public function getCacheController();\n\n  /**\n   * Checks if simple invalidation is enabled for this resource.\n   *\n   * @return bool\n   *   TRUE if simple invalidation is needed.\n   */\n  public function hasSimpleInvalidation();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Decorators/RateLimitDecoratedResource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Decorators\\RateLimitDecoratedResource\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Decorators;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\RateLimit\\RateLimitManager;\n\n/**\n * Class RateLimitDecoratedResource.\n *\n * @package Drupal\\restful\\Plugin\\resource\\Decorators\n */\nclass RateLimitDecoratedResource extends ResourceDecoratorBase implements ResourceDecoratorInterface {\n\n  /**\n   * Authentication manager.\n   *\n   * @var RateLimitManager\n   */\n  protected $rateLimitManager;\n\n  /**\n   * Constructs a Drupal\\Component\\Plugin\\PluginBase object.\n   *\n   * @param ResourceInterface $subject\n   *   The decorated object.\n   * @param RateLimitManager $rate_limit_manager\n   *   Injected rate limit manager.\n   */\n  public function __construct(ResourceInterface $subject, RateLimitManager $rate_limit_manager = NULL) {\n    $this->subject = $subject;\n    $plugin_definition = $subject->getPluginDefinition();\n    $rate_limit_info = empty($plugin_definition['rateLimit']) ? array() : $plugin_definition['rateLimit'];\n    if ($limit = variable_get('restful_global_rate_limit', 0)) {\n      $rate_limit_info['global'] = array(\n        'period' => variable_get('restful_global_rate_period', 'P1D'),\n        'limits' => array(),\n      );\n      foreach (user_roles() as $role_name) {\n        $rate_limit_info['global']['limits'][$role_name] = $limit;\n      }\n    }\n    $this->rateLimitManager = $rate_limit_manager ? $rate_limit_manager : new RateLimitManager($this, $rate_limit_info);\n  }\n\n  /**\n   * Setter for $rateLimitManager.\n   *\n   * @param RateLimitManager $rate_limit_manager\n   *   The rate limit manager.\n   */\n  protected function setRateLimitManager(RateLimitManager $rate_limit_manager) {\n    $this->rateLimitManager = $rate_limit_manager;\n  }\n\n  /**\n   * Getter for $rate_limit_manager.\n   *\n   * @return RateLimitManager\n   *   The rate limit manager.\n   */\n  protected function getRateLimitManager() {\n    return $this->rateLimitManager;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function process() {\n    // This will throw the appropriate exception if needed.\n    $this->getRateLimitManager()->checkRateLimit($this->getRequest());\n    return $this->subject->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->subject->setAccount($account);\n    $this->rateLimitManager->setAccount($account);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Decorators/ResourceDecoratorBase.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Decorators\\ResourceDecoratorBase.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Decorators;\n\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Util\\ExplorableDecoratorInterface;\n\n/**\n * Class ResourceDecoratorBase.\n *\n * @package Drupal\\restful\\Plugin\\resource\\Decorators\n */\nabstract class ResourceDecoratorBase extends PluginBase implements ResourceDecoratorInterface, ExplorableDecoratorInterface {\n\n  /**\n   * The decorated resource.\n   *\n   * @var ResourceInterface\n   */\n  protected $subject;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDecoratedResource() {\n    return $this->subject;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPrimaryResource() {\n    $resource = $this->getDecoratedResource();\n    while ($resource instanceof ResourceDecoratorInterface) {\n      $resource = $resource->getDecoratedResource();\n    }\n    return $resource;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function dataProviderFactory() {\n    return $this->subject->dataProviderFactory();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount($cache = TRUE) {\n    return $this->subject->getAccount($cache);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->subject->setAccount($account);\n    $this->getDataProvider()->setAccount($account);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function switchUserBack() {\n    $this->subject->switchUserBack();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function discover($path = NULL) {\n    return $this->subject->discover($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->subject->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->subject->setRequest($request);\n    // Make sure that the request is updated in the data provider.\n    $this->getDataProvider()->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPath() {\n    return $this->subject->getPath();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPath($path) {\n    $this->subject->setPath($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFieldDefinitions() {\n    return $this->subject->getFieldDefinitions();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDataProvider() {\n    return $this->subject->getDataProvider();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setDataProvider(DataProviderInterface $data_provider = NULL) {\n    $this->subject->setDataProvider($data_provider);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceName() {\n    return $this->subject->getResourceName();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function process() {\n    return $this->subject->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function controllersInfo() {\n    return $this->subject->controllersInfo();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getControllers() {\n    return $this->subject->getControllers();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index($path) {\n    return $this->subject->index($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($path) {\n    return $this->subject->view($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($path) {\n    return $this->subject->create($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($path) {\n    return $this->subject->update($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function replace($path) {\n    return $this->subject->replace($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($path) {\n    $this->subject->remove($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getVersion() {\n    return $this->subject->getVersion();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function versionedUrl($path = '', $options = array(), $version_string = TRUE) {\n    return $this->subject->versionedUrl($path, $options, $version_string);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getConfiguration() {\n    return $this->subject->getConfiguration();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setConfiguration(array $configuration) {\n    $this->subject->setConfiguration($configuration);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function defaultConfiguration() {\n    return $this->subject->defaultConfiguration();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function calculateDependencies() {\n    return $this->subject->calculateDependencies();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function access() {\n    return $this->subject->access();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getControllerFromPath($path = NULL, ResourceInterface $resource = NULL) {\n    return $this->subject->getControllerFromPath($path, $resource ?: $this);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceMachineName() {\n    return $this->subject->getResourceMachineName();\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * This is a decorated resource, get proxy the request until you reach the\n   * annotated resource.\n   */\n  public function getPluginDefinition() {\n    return $this->subject->getPluginDefinition();\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * This is a decorated resource, set proxy the request until you reach the\n   * annotated resource.\n   */\n  public function setPluginDefinition(array $plugin_definition) {\n    $this->subject->setPluginDefinition($plugin_definition);\n    if (!empty($plugin_definition['dataProvider'])) {\n      $this->getDataProvider()->addOptions($plugin_definition['dataProvider']);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function enable() {\n    $this->subject->enable();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function disable() {\n    $this->subject->disable();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isEnabled() {\n    return $this->subject->isEnabled();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setFieldDefinitions(ResourceFieldCollectionInterface $field_definitions) {\n    return $this->subject->setFieldDefinitions($field_definitions);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getUrl(array $options = array(), $keep_query = TRUE, RequestInterface $request = NULL) {\n    return $this->subject->getUrl($options, $keep_query, $request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doGet($path = '', array $query = array()) {\n    $this->setPath($path);\n    $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), $query, RequestInterface::METHOD_GET));\n    return $this->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doPost(array $parsed_body) {\n    return $this->doWrite(RequestInterface::METHOD_POST, '', $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doPatch($path, array $parsed_body) {\n    if (!$path) {\n      throw new BadRequestException('PATCH requires a path. None given.');\n    }\n    return $this->doWrite(RequestInterface::METHOD_PATCH, $path, $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doPut($path, array $parsed_body) {\n    if (!$path) {\n      throw new BadRequestException('PUT requires a path. None given.');\n    }\n    return $this->doWrite(RequestInterface::METHOD_PUT, $path, $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  private function doWrite($method, $path, array $parsed_body) {\n    $this->setPath($path);\n    $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), array(), $method, NULL, FALSE, NULL, array(), array(), array(), $parsed_body));\n    return $this->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doDelete($path) {\n    if (!$path) {\n      throw new BadRequestException('DELETE requires a path. None given.');\n    }\n    $this->setPath($path);\n    $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), array(), RequestInterface::METHOD_DELETE));\n    return $this->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPluginId() {\n    return $this->subject->getPluginId();\n  }\n\n  /**\n   * Checks if the decorated object is an instance of something.\n   *\n   * @param string $class\n   *   Class or interface to check the instance.\n   *\n   * @return bool\n   *   TRUE if the decorated object is an instace of the $class. FALSE\n   *   otherwise.\n   */\n  public function isInstanceOf($class) {\n    if ($this instanceof $class || $this->subject instanceof $class) {\n      return TRUE;\n    }\n    // Check if the decorated resource is also a decorator.\n    if ($this->subject instanceof ExplorableDecoratorInterface) {\n      return $this->subject->isInstanceOf($class);\n    }\n    return FALSE;\n  }\n\n  /**\n   * If any method not declared, then defer it to the decorated field.\n   *\n   * This decorator class is proxying all the calls declared in the\n   * ResourceInterface to the underlying decorated resource. But it is not\n   * doing it for any of the methods of the parents of ResourceInterface.\n   *\n   * With this code, any method that is not declared in the class will try to\n   * make that method call it in the decorated resource.\n   *\n   * @param string $name\n   *   The name of the method that could not be found.\n   * @param array $arguments\n   *   The arguments passed to the method, collected in an array.\n   *\n   * @return mixed\n   *   The result of the call.\n   */\n  public function __call($name, $arguments) {\n    return call_user_func_array(array($this->subject, $name), $arguments);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Decorators/ResourceDecoratorInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Decorators\\ResourceDecoratorInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Decorators;\n\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\ninterface ResourceDecoratorInterface extends ResourceInterface {\n\n  /**\n   * Gets the decorated resource.\n   *\n   * @return ResourceInterface\n   *   The underlying resource.\n   */\n  public function getDecoratedResource();\n\n  /**\n   * Gets the primary resource, the one that is not a decorator.\n   *\n   * @return ResourceInterface\n   *   The resource.\n   */\n  public function getPrimaryResource();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Discovery.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Discovery\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\n/**\n * Class Discovery\n * @package Drupal\\restful_example\\Plugin\\Resource\n *\n * @Resource(\n *   name = \"discovery:1.0\",\n *   resource = \"discovery\",\n *   label = \"Discovery\",\n *   description = \"Discovery plugin.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   discoverable = FALSE,\n *   dataProvider = {\n *     \"idField\": \"name\"\n *   },\n *   menuItem = \"\",\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Discovery extends Resource {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    return array(\n      'label' => array(\n        'property' => 'label',\n      ),\n      'description' => array(\n        'property' => 'description',\n      ),\n      'name' => array(\n        'property' => 'name',\n      ),\n      'resource' => array(\n        'property' => 'resource',\n      ),\n      'majorVersion' => array(\n        'property' => 'majorVersion',\n      ),\n      'minorVersion' => array(\n        'property' => 'minorVersion',\n      ),\n      'self' => array(\n        'callback' => array($this, 'getSelf'),\n      ),\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function dataProviderClassName() {\n    return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderPlug';\n  }\n\n  /**\n   * Returns the URL to the endpoint result.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The plugin's data interpreter.\n   *\n   * @return string\n   *   The RESTful endpoint URL.\n   */\n  public function getSelf(DataInterpreterInterface $interpreter) {\n    if ($menu_item = $interpreter->getWrapper()->get('menuItem')) {\n      $url = variable_get('restful_hook_menu_base_path', 'api') . '/' . $menu_item;\n      return url($url, array('absolute' => TRUE));\n    }\n\n    $base_path = variable_get('restful_hook_menu_base_path', 'api');\n    return url($base_path . '/v' . $interpreter->getWrapper()->get('majorVersion') . '.' . $interpreter->getWrapper()->get('minorVersion') . '/' . $interpreter->getWrapper()->get('resource'), array('absolute' => TRUE));\n  }\n\n  /**\n   * @inheritDoc\n   */\n  public function controllersInfo() {\n    return array(\n      '' => array(\n        // GET returns a list of entities.\n        RequestInterface::METHOD_GET => 'index',\n        RequestInterface::METHOD_HEAD => 'index',\n      ),\n      // We don't know what the ID looks like, assume that everything is the ID.\n      '^.*$' => array(\n        RequestInterface::METHOD_GET => 'view',\n        RequestInterface::METHOD_HEAD => 'view',\n        RequestInterface::METHOD_PUT => array(\n          'callback' => 'replace',\n          'access callback' => 'resourceManipulationAccess',\n        ),\n        RequestInterface::METHOD_DELETE => array(\n          'callback' => 'remove',\n          'access callback' => 'resourceManipulationAccess',\n        ),\n      ),\n    );\n  }\n\n  /**\n   * Helper callback to check authorization for write operations.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @return bool\n   *   TRUE to grant access. FALSE otherwise.\n   */\n  public function resourceManipulationAccess($path) {\n    return user_access('administer restful resources', $this->getAccount());\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/PublicFieldInfo/PublicFieldInfoBase.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoBase.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\n\nclass PublicFieldInfoBase implements PublicFieldInfoInterface {\n\n  /**\n   * Default categories for the field information.\n   *\n   * @var array[]\n   */\n  protected static $defaultSections = array(\n    'info' => array(\n      'label' => '',\n      'description' => '',\n    ),\n    // Describe the data.\n    'data' => array(\n      'type' => NULL,\n      'read_only' => FALSE,\n      'cardinality' => 1,\n      'required' => FALSE,\n    ),\n    // Information about the form element.\n    'form_element' => array(\n      'type' => NULL,\n      'default_value' => '',\n      'placeholder' => '',\n      'size' => NULL,\n      'allowed_values' => NULL,\n    ),\n  );\n\n  /**\n   * Sections for the field information.\n   *\n   * @var array[]\n   */\n  protected $categories = array();\n\n  /**\n   * The name of the public field.\n   *\n   * @var string\n   */\n  protected $fieldName = '';\n\n  /**\n   * PublicFieldInfoBase constructor.\n   *\n   * @param string $field_name\n   *   The name of the field.\n   * @param array[] $sections\n   *   The array of categories information.\n   */\n  public function __construct($field_name, array $sections = array()) {\n    $this->fieldName = $field_name;\n    $sections = drupal_array_merge_deep($this::$defaultSections, $sections);\n    foreach ($sections as $section_name => $section_info) {\n      $this->addCategory($section_name, $section_info);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare() {\n    return $this->categories;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addCategory($category_name, array $section_info) {\n    try {\n      $this->validate($category_name, $section_info);\n      // Process the section info adding defaults if needed.\n      $this->categories[$category_name] = $this->process($category_name, $section_info);\n    }\n    catch (ServerConfigurationException $e) {\n      // If there are validation errors do not add the section.\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getSection($section_name) {\n    return empty($this->categories[$section_name]) ? array() : $this->categories[$section_name];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addSectionDefaults($section_name, array $section_info) {\n    $this->addCategory($section_name, array_merge(\n      $section_info,\n      $this->getSection($section_name)\n    ));\n  }\n\n  /**\n   * Validates the provided data for the section.\n   *\n   * @param string $section_name\n   *   The name of the categories. By default RESTful supports 'info',\n   *   'form_element' and 'data'.\n   * @param array $section_info\n   *   The structured array with the section information.\n   *\n   * @throws ServerConfigurationException\n   *   If the field does not pass validation.\n   */\n  protected function validate($section_name, array $section_info) {\n    if ($section_name == 'info') {\n      $this->validateInfo($section_info);\n    }\n    elseif ($section_name == 'data') {\n      $this->validateData($section_info);\n    }\n    elseif ($section_name == 'form_element') {\n      $this->validateFormElement($section_info);\n    }\n  }\n\n  /**\n   * Processes the provided data for the section.\n   *\n   * @param string $section_name\n   *   The name of the categories. By default RESTful supports 'info',\n   *   'form_element' and 'data'.\n   * @param array $section_info\n   *   The structured array with the section information.\n   *\n   * @returns array\n   *   The processed section info.\n   */\n  protected function process($section_name, array $section_info) {\n    if ($section_name == 'data') {\n      if ($section_info['type'] == 'string') {\n        $section_info['size'] = isset($section_info['size']) ? $section_info['size'] : 255;\n      }\n    }\n    elseif ($section_name == 'form_element') {\n      // Default title and description to the ones in the 'info' section.\n      if (empty($section_info['title'])) {\n        $section_info['title'] = empty($this->categories['info']['title']) ? $this->fieldName : $this->categories['info']['title'];\n        if (!empty($this->categories['info']['description'])) {\n          $section_info['description'] = $this->categories['info']['description'];\n        }\n      }\n    }\n\n    return $section_info;\n  }\n\n  /**\n   * Validates the info section.\n   *\n   * @param array $section_info\n   *   The structured array with the section information.\n   *\n   * @throws ServerConfigurationException\n   *   If the field does not pass validation.\n   */\n  protected function validateInfo(array $section_info) {\n    if (empty($section_info['label'])) {\n      throw new ServerConfigurationException(sprintf('The label information is missing for this field: %s.', $this->fieldName));\n    }\n  }\n\n  /**\n   * Validates the info section.\n   *\n   * @param array $section_info\n   *   The structured array with the section information.\n   *\n   * @throws ServerConfigurationException\n   *   If the field does not pass validation.\n   */\n  protected function validateData(array $section_info) {\n    if (empty($section_info['type'])) {\n      throw new ServerConfigurationException(sprintf('The schema information is not valid for this field: %s.', $this->fieldName));\n    }\n  }\n\n  /**\n   * Validates the info section.\n   *\n   * @param array $section_info\n   *   The structured array with the section information.\n   *\n   * @throws ServerConfigurationException\n   *   If the field does not pass validation.\n   */\n  protected function validateFormElement(array $section_info) {\n    if (empty($section_info['type'])) {\n      throw new ServerConfigurationException(sprintf('The form element information is not valid for this field: %s.', $this->fieldName));\n    }\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/PublicFieldInfo/PublicFieldInfoEntity.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoEntity.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo;\n\nclass PublicFieldInfoEntity extends PublicFieldInfoBase implements PublicFieldInfoEntityInterface {\n\n  /**\n   * The field name or property in the Drupal realm.\n   *\n   * @var string\n   */\n  protected $property;\n\n  /**\n   * The entity type.\n   *\n   * @var string\n   */\n  protected $entityType;\n\n  /**\n   * The bundle.\n   *\n   * @var string\n   */\n  protected $bundle;\n\n  /**\n   * PublicFieldInfoBase constructor.\n   *\n   * @param string $field_name\n   *   The name of the field.\n   * @param string $property\n   *   The name of the Drupal field.\n   * @param string $entity_type\n   *   The entity type.\n   * @param string $bundle\n   *   The bundle.\n   * @param array[] $sections\n   *   The array of categories information.\n   */\n  public function __construct($field_name, $property, $entity_type, $bundle, array $sections = array()) {\n    parent::__construct($field_name, $sections);\n    $this->property = $property;\n    $this->entityType = $entity_type;\n    $this->bundle = $bundle;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFormSchemaAllowedValues() {\n    if (!module_exists('options')) {\n      return NULL;\n    }\n    $field_name = $this->property;\n    if (!$field_info = field_info_field($field_name)) {\n      return NULL;\n    }\n    if (!$field_instance = field_info_instance($this->entityType, $field_name, $this->bundle)) {\n      return NULL;\n    }\n    if (!$this::formSchemaHasAllowedValues($field_info, $field_instance)) {\n      // Field doesn't have allowed values.\n      return NULL;\n    }\n    // Use Field API's widget to get the allowed values.\n    $type = str_replace('options_', '', $field_instance['widget']['type']);\n    $multiple = $field_info['cardinality'] > 1 || $field_info['cardinality'] == FIELD_CARDINALITY_UNLIMITED;\n    // Always pass TRUE for \"required\" and \"has_value\", as we don't want to get\n    // the \"none\" option.\n    $required = TRUE;\n    $has_value = TRUE;\n    $properties = _options_properties($type, $multiple, $required, $has_value);\n    // Mock an entity.\n    $values = array();\n    $entity_info = $this->getEntityInfo();\n    if (!empty($entity_info['entity keys']['bundle'])) {\n      // Set the bundle of the entity.\n      $values[$entity_info['entity keys']['bundle']] = $this->bundle;\n    }\n    $entity = entity_create($this->entityType, $values);\n    return _options_get_options($field_info, $field_instance, $properties, $this->entityType, $entity);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFormSchemaAllowedType() {\n    if (!module_exists('options')) {\n      return NULL;\n    }\n    $field_name = $this->property;\n    if (!$field_info = field_info_field($field_name)) {\n      return NULL;\n    }\n    if (!$field_instance = field_info_instance($this->entityType, $field_name, $this->bundle)) {\n      return NULL;\n    }\n    return $field_instance['widget']['type'];\n  }\n\n  /**\n   * Get the entity info for the current entity the endpoint handling.\n   *\n   * @param string $type\n   *   Optional. The entity type.\n   *\n   * @return array\n   *   The entity info.\n   *\n   * @see entity_get_info().\n   */\n  protected function getEntityInfo($type = NULL) {\n    return entity_get_info($type ? $type : $this->entityType);\n  }\n\n  /**\n   * Determines if a field has allowed values.\n   *\n   * If Field is reference, and widget is autocomplete, so for performance\n   * reasons we do not try to grab all the referenced entities.\n   *\n   * @param array $field\n   *   The field info array.\n   * @param array $field_instance\n   *   The instance info array.\n   *\n   * @return bool\n   *   TRUE if a field should be populated with the allowed values.\n   */\n  protected static function formSchemaHasAllowedValues($field, $field_instance) {\n    $field_types = array(\n      'entityreference',\n      'taxonomy_term_reference',\n      'field_collection',\n      'commerce_product_reference',\n    );\n    $widget_types = array(\n      'taxonomy_autocomplete',\n      'entityreference_autocomplete',\n      'entityreference_autocomplete_tags',\n      'commerce_product_reference_autocomplete',\n    );\n    return !in_array($field['type'], $field_types) || !in_array($field_instance['widget']['type'], $widget_types);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/PublicFieldInfo/PublicFieldInfoEntityInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoEntityInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo;\n\ninterface PublicFieldInfoEntityInterface extends PublicFieldInfoInterface {\n\n  /**\n   * Get allowed values for the form schema.\n   *\n   * Using Field API's \"Options\" module to get the allowed values.\n   *\n   * @return mixed\n   *   The allowed values or NULL if none found.\n   */\n  public function getFormSchemaAllowedValues();\n\n  /**\n   * Get the form type for the form schema.\n   *\n   * Using Field API's \"Options\" module to get the allowed values.\n   *\n   * @return mixed\n   *   The form element type.\n   */\n  public function getFormSchemaAllowedType();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/PublicFieldInfo/PublicFieldInfoInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo;\n\ninterface PublicFieldInfoInterface {\n\n  /**\n   * Generates an structured array ready to be encoded.\n   *\n   * @return array\n   *   The structured array of information.\n   */\n  public function prepare();\n\n  /**\n   * Add categories to the field info.\n   *\n   * @param string $category_name\n   *   The name of the categories. By default RESTful suports 'info',\n   *   'form_element' and 'data'.\n   * @param array $section_info\n   *   The structured array with the section information.\n   */\n  public function addCategory($category_name, array $section_info);\n\n  /**\n   * Gets the section.\n   *\n   * @param string $section_name\n   *   The name of the section. By default RESTful suports 'info',\n   *   'form_element' and 'data'.\n   *\n   * @return array\n   *   The structured array with the section information.\n   */\n  public function getSection($section_name);\n\n  /**\n   * Merges default data in a section if it's not populated.\n   *\n   * @param string $section_name\n   *   The name of the categories. By default RESTful suports 'info',\n   *   'form_element' and 'data'.\n   * @param array $section_info\n   *   The structured array with the section information.\n   */\n  public function addSectionDefaults($section_name, array $section_info);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/PublicFieldInfo/PublicFieldInfoNull.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoNull.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo;\n\nclass PublicFieldInfoNull implements PublicFieldInfoInterface {\n\n  /**\n   * PublicFieldInfoBase constructor.\n   *\n   * @param string $field_name\n   *   The name of the field.\n   * @param array[] $sections\n   *   The array of categories information.\n   */\n  public function __construct($field_name, array $sections = array()) {\n    $this->fieldName = $field_name;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function prepare() {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addCategory($category_name, array $section_info) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getSection($section_name) {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addSectionDefaults($section_name, array $section_info) {}\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceField.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\ResourceField.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\nclass ResourceField extends ResourceFieldBase implements ResourceFieldInterface {\n\n  /**\n   * Constructor.\n   *\n   * @param array $field\n   *   Contains the field values.\n   *\n   * @throws ServerConfigurationException\n   */\n  public function __construct(array $field, RequestInterface $request) {\n    $this->setRequest($request);\n    if (empty($field['public_name'])) {\n      throw new ServerConfigurationException('No public name provided in the field mappings.');\n    }\n    $this->publicName = $field['public_name'];\n    $this->accessCallbacks = isset($field['access_callbacks']) ? $field['access_callbacks'] : $this->accessCallbacks;\n    $this->property = isset($field['property']) ? $field['property'] : $this->property;\n    // $this->column = isset($field['column']) ? $field['column'] : $this->column;\n    $this->callback = isset($field['callback']) ? $field['callback'] : $this->callback;\n    $this->processCallbacks = isset($field['process_callbacks']) ? $field['process_callbacks'] : $this->processCallbacks;\n    $this->resource = isset($field['resource']) ? $field['resource'] : $this->resource;\n    $this->methods = isset($field['methods']) ? $field['methods'] : $this->methods;\n    // Store the definition, useful to access custom keys on custom resource\n    // fields.\n    $this->definition = $field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create(array $field, RequestInterface $request = NULL) {\n    $request = $request ?: restful()->getRequest();\n    if ($class_name = static::fieldClassName($field)) {\n      if ($class_name != get_called_class() && $class_name != '\\\\' . get_called_class()) {\n        // Call the create factory in the derived class.\n        return call_user_func_array(array($class_name, 'create'), array(\n          $field,\n          $request,\n          new static($field, $request),\n        ));\n      }\n    }\n    // If no other class was found, then use the current one.\n    $resource_field = new static($field, $request);\n    $resource_field->addDefaults();\n    return $resource_field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function value(DataInterpreterInterface $interpreter) {\n    if ($callback = $this->getCallback()) {\n      return ResourceManager::executeCallback($callback, array($interpreter));\n    }\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($value, DataInterpreterInterface $interpreter) {\n    // ResourceField only supports callbacks, so no set is possible.\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function access($op, DataInterpreterInterface $interpreter) {\n    foreach ($this->getAccessCallbacks() as $callback) {\n      $result = ResourceManager::executeCallback($callback, array(\n        $op,\n        $this,\n        $interpreter,\n      ));\n\n      if ($result == ResourceFieldBase::ACCESS_DENY) {\n        return FALSE;\n      }\n    }\n\n    return TRUE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addDefaults() {\n    // Almost all the defaults come are applied by the object's property\n    // defaults.\n\n    if (!$resource = $this->getResource()) {\n      return;\n    }\n    // Expand array to be verbose.\n    if (!is_array($resource)) {\n      $resource = array('name' => $resource);\n    }\n\n    // Set default value.\n    $resource += array(\n      'fullView' => TRUE,\n    );\n\n    // Set the default value for the version of the referenced resource.\n    if (!isset($resource['majorVersion']) || !isset($resource['minorVersion'])) {\n      list($major_version, $minor_version) = restful()\n        ->getResourceManager()\n        ->getResourceLastVersion($resource['name']);\n      $resource['majorVersion'] = $major_version;\n      $resource['minorVersion'] = $minor_version;\n    }\n\n    $this->setResource($resource);\n  }\n\n  /**\n   * Get the class name to use based on the field definition.\n   *\n   * @param array $field_definition\n   *   The processed field definition with the user values.\n   *\n   * @return string\n   *   The class name to use. If the class name is empty or does not implement\n   *   ResourceFieldInterface then ResourceField will be used. NULL if nothing\n   *   was found.\n   */\n  public static function fieldClassName(array $field_definition) {\n    if (!empty($field_definition['class'])) {\n      $class_name = $field_definition['class'];\n    }\n    // Search for indicators that this is a ResourceFieldEntityInterface.\n    elseif (\n      !empty($field_definition['sub_property']) ||\n      !empty($field_definition['formatter']) ||\n      !empty($field_definition['wrapper_method']) ||\n      !empty($field_definition['wrapper_method_on_entity']) ||\n      !empty($field_definition['column']) ||\n      !empty($field_definition['image_styles']) ||\n      (!empty($field_definition['property']) ? field_info_field($field_definition['property']) : NULL)\n    ) {\n      $class_name = '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntity';\n    }\n    elseif (!empty($field_definition['property'])) {\n      $class_name = '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldKeyValue';\n    }\n\n    if (\n      !empty($class_name) &&\n      class_exists($class_name) &&\n      in_array(\n        'Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface',\n        class_implements($class_name)\n      )\n    ) {\n      return $class_name;\n    }\n\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function compoundDocumentId(DataInterpreterInterface $interpreter) {\n    // Since this kind of field can be anything, just return the value.\n    return $this->value($interpreter);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(DataInterpreterInterface $interpreter) {\n    return $this->executeProcessCallbacks($this->value($interpreter));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCardinality() {\n    // Default to cardinality of 1.\n    return 1;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCardinality($cardinality) {\n    $this->cardinality = $cardinality;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldBase.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoBase;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoNull;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\nabstract class ResourceFieldBase implements ResourceFieldInterface {\n\n  /**\n   * Return this value from public field access callbacks to allow access.\n   */\n  const ACCESS_ALLOW = 'allow';\n\n  /**\n   * Return this value from public field access callbacks to deny access.\n   */\n  const ACCESS_DENY = 'deny';\n\n  /**\n   * Return this value from public field access callbacks to not affect access.\n   */\n  const ACCESS_IGNORE = NULL;\n\n\n  /**\n   * Contains the public field name.\n   */\n  protected $publicName;\n\n  /**\n   * An array of callbacks to determine if user has access to the property. Note\n   * that this callback is on top of the access provided by entity API, and is\n   * used for convenience, where for example write operation on a property\n   * should be denied only on certain request conditions. The Passed arguments\n   * are:\n   *   - op: The operation that access should be checked for. Can be \"view\" or\n   *     \"edit\".\n   *   - public_field_name: The name of the public field.\n   *   - property_wrapper: The wrapped property.\n   *   - wrapper: The wrapped entity.\n   *\n   * @var array\n   */\n  protected $accessCallbacks = array();\n\n  /**\n   * The entity property (e.g. \"title\", \"nid\").\n   *\n   * @var string\n   */\n  protected $property;\n\n  /**\n   * A callable callback to get a computed value. The wrapped entity is passed\n   * as argument. Defaults To FALSE. The callback function receive as first\n   * argument the entity.\n   *\n   * @var mixed\n   */\n  protected $callback;\n\n  /**\n   * An array of callbacks to perform on the returned value, or an array with\n   * the object and method.\n   *\n   * @var array\n   */\n  protected $processCallbacks = array();\n\n  /**\n   * This property can be assigned only to an entity reference field. Array of\n   * restful resources keyed by the target bundle. For example, if the field is\n   * referencing a node entity, with \"Article\" and \"Page\" bundles, we are able\n   * to map those bundles to their related resource. Items with bundles that\n   * were not explicitly set would be ignored.\n   *\n   * It is also possible to pass an array as the value, with:\n   *   - \"name\": The resource name.\n   *   - \"fullView\": Determines if the referenced resource should be rendered,\n   *   or just the referenced ID(s) to appear. Defaults to TRUE.\n   *   array(\n   *     // Shorthand.\n   *     'article' => 'articles',\n   *     // Verbose\n   *     'page' => array(\n   *       'name' => 'pages',\n   *       'fullView' => FALSE,\n   *     ),\n   *   );\n   *\n   * @var array\n   */\n  protected $resource = array();\n\n  /**\n   * A generic array storage.\n   *\n   * @var array\n   */\n  protected $metadata = array();\n\n  /**\n   * The HTTP methods where this field applies.\n   *\n   * This replaces the create_or_update_passthrough feature. Defaults to all.\n   *\n   * @var array\n   */\n  protected $methods = array(\n    RequestInterface::METHOD_GET,\n    RequestInterface::METHOD_HEAD,\n    RequestInterface::METHOD_POST,\n    RequestInterface::METHOD_PUT,\n    RequestInterface::METHOD_PATCH,\n    RequestInterface::METHOD_OPTIONS,\n  );\n\n  /**\n   * The request object to be used.\n   *\n   * @var RequestInterface\n   */\n  protected $request;\n\n  /**\n   * The field definition array.\n   *\n   * Use with caution.\n   *\n   * @var array\n   */\n  protected $definition = array();\n\n  /**\n   * Information about the field.\n   *\n   * @var PublicFieldInfoInterface\n   */\n  protected $publicFieldInfo;\n\n  /**\n   * Holds the field cardinality.\n   *\n   * @var int\n   */\n  protected $cardinality;\n\n  /**\n   * Get the request in the data provider.\n   *\n   * @return RequestInterface\n   *   The request.\n   */\n  public function getRequest() {\n    return $this->request;\n  }\n\n  /**\n   * Set the request.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->request = $request;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPublicName() {\n    return $this->publicName;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPublicName($public_name) {\n    $this->publicName = $public_name;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccessCallbacks() {\n    return $this->accessCallbacks;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccessCallbacks($access_callbacks) {\n    $this->accessCallbacks = $access_callbacks;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProperty() {\n    return $this->property;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProperty($property) {\n    $this->property = $property;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCallback() {\n    return $this->callback;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCallback($callback) {\n    $this->callback = $callback;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProcessCallbacks() {\n    return $this->processCallbacks;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProcessCallbacks($process_callbacks) {\n    $this->processCallbacks = $process_callbacks;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResource() {\n    return $this->resource;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResource($resource) {\n    $this->resource = $resource;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMethods() {\n    return $this->methods;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setMethods($methods) {\n    foreach ($methods as $method) {\n      if (Request::isValidMethod($method)) {\n        throw new ServerConfigurationException(sprintf('The method %s in the field resource mapping is not valid.', $method));\n      }\n    }\n    $this->methods = $methods;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function id() {\n    return $this->publicName;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isComputed() {\n    return !$this->getProperty();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public final static function isArrayNumeric(array $input) {\n    $keys = array_keys($input);\n    foreach ($keys as $key) {\n      if (!ctype_digit((string) $key)) {\n        return FALSE;\n      }\n    }\n    return isset($keys[0]) ? $keys[0] == 0 : TRUE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addMetadata($key, $value) {\n    $path = explode(':', $key);\n    $leave = array_pop($path);\n    $element = &$this->internalMetadataElement($key);\n\n    $element[$leave] = $value;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMetadata($key) {\n    $path = explode(':', $key);\n    $leave = array_pop($path);\n    $element = $this->internalMetadataElement($key);\n\n    return isset($element[$leave]) ? $element[$leave] : NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDefinition() {\n    return $this->definition;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function executeProcessCallbacks($value) {\n    $process_callbacks = $this->getProcessCallbacks();\n    if (!isset($value) || empty($process_callbacks)) {\n      return $value;\n    }\n    foreach ($process_callbacks as $process_callback) {\n      $value = ResourceManager::executeCallback($process_callback, array($value));\n    }\n    return $value;\n  }\n\n  /**\n   * Returns the last array element from the nested namespace array.\n   *\n   * Searches in the metadata nested array the element in the data tree pointed\n   * by the colon separated key. If the key goes through a non-existing path, it\n   * initalize an empty array. The reference to that element is returned for\n   * reading and writing purposes.\n   *\n   * @param string $key\n   *   The namespaced key.\n   *\n   * @return array\n   *   The reference to the array element.\n   */\n  protected function &internalMetadataElement($key) {\n    // If there is a namespace, then use it to do nested arrays.\n    $path = explode(':', $key);\n    array_pop($path);\n    $element = &$this->metadata;\n    foreach ($path as $path_item) {\n      if (!isset($element[$path_item])) {\n        // Initialize an empty namespace.\n        $element[$path_item] = array();\n      }\n      $element = $element[$path_item];\n    }\n    return $element;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPublicFieldInfo() {\n    return $this->publicFieldInfo;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPublicFieldInfo(PublicFieldInfoInterface $public_field_info) {\n    $this->publicFieldInfo = $public_field_info;\n  }\n\n  /**\n   * Basic auto discovery information.\n   *\n   * @return array\n   *   The array of information ready to be encoded.\n   */\n  public function autoDiscovery() {\n    return $this\n      ->getPublicFieldInfo()\n      ->prepare();\n  }\n\n  /**\n   * Returns the basic discovery information for a given field.\n   *\n   * @param string $name\n   *   The name of the public field.\n   *\n   * @return array\n   *   The array of information ready to be encoded.\n   */\n  public static function emptyDiscoveryInfo($name) {\n    $info = new PublicFieldInfoNull($name);\n    return $info->prepare();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldCollection.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Resource;\n\nclass ResourceFieldCollection implements ResourceFieldCollectionInterface {\n\n  /**\n   * The public fields.\n   *\n   * Every item contains a ResourceFieldInterface.\n   *\n   * @var array\n   */\n  protected $fields = array();\n\n  /**\n   * The data interpreter for all the fields in this field collection.\n   *\n   * @var DataInterpreterInterface $interpreter\n   */\n  protected $interpreter;\n\n  /**\n   * Contains the resource field representing the ID.\n   *\n   * @var ResourceFieldInterface $idField;\n   */\n  protected $idField;\n\n  /**\n   * The contexts for the field collection.\n   *\n   * @var ArrayCollection[]\n   */\n  protected $context;\n\n  /**\n   * List of fields that are allowed in the output.\n   *\n   * @var string[]\n   */\n  protected $limitFields = array();\n\n  /**\n   * Contains the resource ID this field collection is for.\n   *\n   * @var string\n   */\n  protected $resourceId;\n\n  /**\n   * Constructor.\n   *\n   * Creates the collection and each one of the field resource fields in it\n   * based on the configuration array.\n   *\n   * @param array $fields\n   *   Array with the optional values:\n   *   - \"access_callbacks\": An array of callbacks to determine if user has access\n   *     to the property. Note that this callback is on top of the access provided by\n   *     entity API, and is used for convenience, where for example write\n   *     operation on a property should be denied only on certain request\n   *     conditions. The Passed arguments are:\n   *     - op: The operation that access should be checked for. Can be \"view\" or\n   *       \"edit\".\n   *     - public_field_name: The name of the public field.\n   *     - property_wrapper: The wrapped property.\n   *     - wrapper: The wrapped entity.\n   *   - \"property\": The entity property (e.g. \"title\", \"nid\").\n   *   - \"sub_property\": A sub property name of a property to take from it the\n   *     content. This can be used for example on a text field with filtered text\n   *     input format where we would need to do $wrapper->body->value->value().\n   *     Defaults to FALSE.\n   *   - \"formatter\": Used for rendering the value of a configurable field using\n   *     Drupal field API's formatter. The value is the $display value that is\n   *     passed to field_view_field().\n   *   - \"wrapper_method\": The wrapper's method name to perform on the field.\n   *     This can be used for example to get the entity label, by setting the\n   *     value to \"label\". Defaults to \"value\".\n   *   - \"wrapper_method_on_entity\": A Boolean to indicate on what to perform\n   *     the wrapper method. If TRUE the method will perform on the entity (e.g.\n   *     $wrapper->label()) and FALSE on the property or sub property\n   *     (e.g. $wrapper->field_reference->label()). Defaults to FALSE.\n   *   - \"column\": If the property is a field, set the column that would be used\n   *     in queries. For example, the default column for a text field would be\n   *     \"value\". Defaults to the first column returned by field_info_field(),\n   *     otherwise FALSE.\n   *   - \"callback\": A callable callback to get a computed value. The wrapped\n   *     entity is passed as argument. Defaults To FALSE.\n   *     The callback function receive as first argument the entity\n   *     EntityMetadataWrapper object.\n   *   - \"process_callbacks\": An array of callbacks to perform on the returned\n   *     value, or an array with the object and method. Defaults To empty array.\n   *   - \"resource\": This property can be assigned only to an entity reference\n   *     field. Array of restful resources keyed by the target bundle. For\n   *     example, if the field is referencing a node entity, with \"Article\" and\n   *     \"Page\" bundles, we are able to map those bundles to their related\n   *     resource. Items with bundles that were not explicitly set would be\n   *     ignored.\n   *     It is also possible to pass an array as the value, with:\n   *     - \"name\": The resource name.\n   *     - \"fullView\": Determines if the referenced resource should be rendered\n   *     or just the referenced ID(s) to appear. Defaults to TRUE.\n   *     array(\n   *       // Shorthand.\n   *       'article' => 'articles',\n   *       // Verbose\n   *       'page' => array(\n   *         'name' => 'pages',\n   *         'fullView' => FALSE,\n   *       ),\n   *     );\n   *   - \"create_or_update_passthrough\": Determines if a public field that isn't\n   *     mapped to any property or field, may be passed upon create or update\n   *     of an entity. Defaults to FALSE.\n   * @param RequestInterface $request\n   *   The request.\n   */\n  public function __construct(array $fields = array(), RequestInterface $request) {\n    foreach ($fields as $public_name => $field_info) {\n      $field_info['public_name'] = $public_name;\n      // The default values are added.\n      if (empty($field_info['resource'])) {\n        $resource_field = ResourceField::create($field_info, $request);\n      }\n      else {\n        $resource_field = ResourceFieldResource::create($field_info, $request);\n      }\n      $this->fields[$resource_field->id()] = $resource_field;\n    }\n    $this->idField = empty($fields['id']) ? NULL : $this->get('id');\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function factory(array $fields = array(), RequestInterface $request = NULL) {\n    // TODO: Explore the possibility to change factory methods by using FactoryInterface.\n    return new static($fields, $request ?: restful()->getRequest());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create() {\n    static::factory(static::getInfo());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get($key) {\n    return isset($this->fields[$key]) ? $this->fields[$key] : NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($key, ResourceFieldInterface $field) {\n    $this->fields[$key] = $field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function current() {\n    return current($this->fields);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function next() {\n    return next($this->fields);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function key() {\n    return key($this->fields);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function valid() {\n    $key = key($this->fields);\n    return $key !== NULL && $key !== FALSE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function rewind() {\n    return reset($this->fields);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function count() {\n    return count($this->fields);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getInterpreter() {\n    return $this->interpreter;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setInterpreter($interpreter) {\n    $this->interpreter = $interpreter;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getIdField() {\n    return $this->idField;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setIdField($id_field) {\n    $this->idField = $id_field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceName() {\n    $resource_id = $this->getResourceId();\n    $pos = strpos($resource_id, Resource::DERIVATIVE_SEPARATOR);\n    return $pos === FALSE ? $resource_id : substr($resource_id, 0, $pos);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceId() {\n    return $this->resourceId;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResourceId($resource_id) {\n    $this->resourceId = $resource_id;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function evalFilter(array $filter) {\n    // Initialize to TRUE for AND and FALSE for OR (neutral value).\n    $match = $filter['conjunction'] == 'AND';\n    for ($index = 0; $index < count($filter['value']); $index++) {\n      if (!$resource_field = $this->get($filter['public_field'])) {\n        // If the field is unknown don't use se filter.\n        return TRUE;\n      }\n      $filter_value = $resource_field->value($this->getInterpreter());\n      if (is_null($filter_value)) {\n        // Property doesn't exist on the plugin, so filter it out.\n        return FALSE;\n      }\n\n      if ($filter['conjunction'] == 'OR') {\n        $match = $match || $this::evaluateExpression($filter_value, $filter['value'][$index], $filter['operator'][$index]);\n        if ($match) {\n          break;\n        }\n      }\n      else {\n        $match = $match && $this::evaluateExpression($filter_value, $filter['value'][$index], $filter['operator'][$index]);\n        if (!$match) {\n          break;\n        }\n      }\n    }\n    return $match;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setContext($context_id, ArrayCollection $context) {\n    $this->context[$context_id] = $context;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getContext() {\n    return $this->context;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getLimitFields() {\n    return $this->limitFields;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setLimitFields($limit_fields) {\n    $this->limitFields = $limit_fields;\n    // Make sure that the nested fields are added appropriately.\n    foreach ($limit_fields as $limit_field) {\n      $parts = explode('.', $limit_field);\n      $this->limitFields[] = $parts[0];\n    }\n    $this->limitFields = array_unique($this->limitFields);\n  }\n\n  /**\n   * Evaluate a simple expression.\n   *\n   * @param mixed $value1\n   *   The first value.\n   * @param mixed $value2\n   *   The second value.\n   * @param string $operator\n   *   The operator.\n   *\n   * @return bool\n   *   TRUE or FALSE based on the evaluated expression.\n   *\n   * @throws BadRequestException\n   */\n  protected static function evaluateExpression($value1, $value2, $operator) {\n    switch($operator) {\n      case '=':\n        return $value1 == $value2;\n\n      case '<':\n        return $value1 < $value2;\n\n      case '>':\n        return $value1 > $value2;\n\n      case '>=':\n        return $value1 >= $value2;\n\n      case '<=':\n        return $value1 <= $value2;\n\n      case '<>':\n      case '!=':\n        return $value1 != $value2;\n\n      case 'IN':\n        return in_array($value1, $value2);\n\n      case 'BETWEEN':\n        return $value1 >= $value2[0] && $value1 >= $value2[1];\n    }\n    return FALSE;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldCollectionInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\ninterface ResourceFieldCollectionInterface extends \\Iterator, \\Countable {\n\n  /**\n   * Factory.\n   *\n   * Creates the collection and each one of the field resource fields in it\n   * based on the configuration array.\n   *\n   * @param array $fields\n   *   An array of field mappings.\n   * @param RequestInterface $request\n   *   The request.\n   *\n   * @return ResourceFieldCollectionInterface\n   *   The newly created object.\n   */\n  public static function factory(array $fields = array(), RequestInterface $request = NULL);\n\n  /**\n   * Factory.\n   *\n   * Creates the collection based on the implementation of the static::getInfo\n   * method.\n   *\n   * @return ResourceFieldCollectionInterface\n   *   The newly created object.\n   */\n  public static function create();\n\n  /**\n   * Default get info implementation.\n   *\n   * This is the method the implementers need to overwrite in order to provide\n   * their own field definitions.\n   *\n   * @return array\n   *   The array with field mappings.\n   */\n  public static function getInfo();\n\n  /**\n   * Get an element of the collection by its key.\n   *\n   * @param string $key\n   *   The key of the field.\n   *\n   * @return ResourceFieldInterface\n   *   The requested field.\n   */\n  public function get($key);\n\n  /**\n   * Sets a field in the collection.\n   *\n   * @param string $key\n   *   The key of the field.\n   * @param ResourceFieldInterface $field\n   *   The field to set.\n   */\n  public function set($key, ResourceFieldInterface $field);\n\n  /**\n   * Sets the data interpreter.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The interpreter.\n   */\n  public function setInterpreter($interpreter);\n\n  /**\n   * Gets the data interpreter.\n   *\n   * @return DataInterpreterInterface\n   *   The interpreter.\n   */\n  public function getInterpreter();\n\n  /**\n   * Get the resource field that will return the ID.\n   *\n   * @return ResourceFieldInterface\n   *   The field.\n   */\n  public function getIdField();\n\n  /**\n   * Set the resource field that will return the ID.\n   *\n   * @param ResourceFieldInterface $id_field\n   *   The field to set.\n   */\n  public function setIdField($id_field);\n\n  /**\n   * Evaluate a parsed filter on a field collection.\n   *\n   * @param array $filter\n   *   The parsed filter.\n   *\n   * @return bool\n   *   TRUE if the collection matches the filter. FALSE otherwise.\n   */\n  public function evalFilter(array $filter);\n\n  /**\n   * Sets a context for the group of fields.\n   *\n   * @param string $context_id\n   *   The context identifier. Ex: 'cache_fragments'.\n   * @param ArrayCollection $context\n   *   The context.\n   */\n  public function setContext($context_id, ArrayCollection $context);\n\n  /**\n   * Gets a context for the group of fields.\n   *\n   * @return ArrayCollection[]\n   *   The context.\n   */\n  public function getContext();\n\n  /**\n   * Get the list of fields.\n   *\n   * @return string[]\n   *   The fields.\n   */\n  public function getLimitFields();\n\n  /**\n   * Set the limit fields.\n   *\n   * @param string[] $limit_fields\n   *   The list of fields to set.\n   */\n  public function setLimitFields($limit_fields);\n\n  /**\n   * Gets the resource name.\n   *\n   * @return string\n   *   The resource name.\n   */\n  public function getResourceName();\n\n  /**\n   * Gets the resource ID.\n   *\n   * @return string\n   *   The resource ID.\n   */\n  public function getResourceId();\n\n  /**\n   * Sets the resource ID.\n   *\n   * @param string $resource_id\n   *   The resource ID.\n   */\n  public function setResourceId($resource_id);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldDbColumn.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldDbColumn.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\nclass ResourceFieldDbColumn extends ResourceField implements ResourceFieldDbColumnInterface {\n\n  /**\n   * Column for query.\n   * @var string\n   */\n  protected $columnForQuery;\n\n  /**\n   * Constructor.\n   *\n   * @param array $field\n   *   Contains the field values.\n   *\n   * @throws ServerConfigurationException\n   */\n  public function __construct(array $field, RequestInterface $request) {\n    parent::__construct($field, $request);\n    $this->columnForQuery = empty($field['columnForQuery']) ? $this->getProperty() : $field['columnForQuery'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create(array $field, RequestInterface $request = NULL) {\n    $resource_field = new static($field, $request ?: restful()->getRequest());\n    $resource_field->addDefaults();\n    return $resource_field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getColumnForQuery() {\n    return $this->columnForQuery;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function value(DataInterpreterInterface $interpreter) {\n    $value = parent::value($interpreter);\n    if (isset($value)) {\n      return $value;\n    }\n    return $interpreter->getWrapper()->get($this->getProperty());\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldDbColumnInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldDbColumnInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\ninterface ResourceFieldDbColumnInterface extends ResourceFieldInterface {\n\n  /**\n   * Gets the column for the query.\n   *\n   * @return string\n   *   The name of the column.\n   */\n  public function getColumnForQuery();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntity.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntity\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProvider;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoEntity;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoEntityInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class ResourceFieldEntity.\n *\n * @package Drupal\\restful\\Plugin\\resource\\Field\n */\nclass ResourceFieldEntity implements ResourceFieldEntityInterface {\n\n  /**\n   * Decorated resource field.\n   *\n   * @var ResourceFieldInterface\n   */\n  protected $decorated;\n\n  /**\n   * A copy of the underlying property.\n   *\n   * This is duplicated here for performance reasons.\n   *\n   * @var string\n   */\n  protected $property;\n\n  /**\n   * A sub property name of a property to take from it the content.\n   *\n   * This can be used for example on a text field with filtered text input\n   * format where we would need to do $wrapper->body->value->value().\n   *\n   * @var string\n   */\n  protected $subProperty;\n\n  /**\n   * Used for rendering the value of a configurable field using Drupal field\n   * API's formatter. The value is the $display value that is passed to\n   * field_view_field().\n   *\n   * @var array\n   */\n  protected $formatter;\n\n  /**\n   * The wrapper's method name to perform on the field. This can be used for\n   * example to get the entity label, by setting the value to \"label\". Defaults\n   * to \"value\".\n   *\n   * @var string\n   */\n  protected $wrapperMethod = 'value';\n\n  /**\n   * A Boolean to indicate on what to perform the wrapper method. If TRUE the\n   * method will perform on the entity (e.g. $wrapper->label()) and FALSE on the\n   * property or sub property (e.g. $wrapper->field_reference->label()).\n   *\n   * @var bool\n   */\n  protected $wrapperMethodOnEntity = FALSE;\n\n  /**\n   * If the property is a field, set the column that would be used in queries.\n   * For example, the default column for a text field would be \"value\". Defaults\n   * to the first column returned by field_info_field(), otherwise FALSE.\n   *\n   * @var string\n   */\n  protected $column;\n\n  /**\n   * Array of image styles to apply to this resource field maps to an image\n   * field.\n   *\n   * @var array\n   */\n  protected $imageStyles = array();\n\n  /**\n   * The entity type.\n   *\n   * @var string\n   */\n  protected $entityType;\n\n  /**\n   * The bundle name.\n   *\n   * @var string\n   */\n  protected $bundle;\n\n  /**\n   * Constructor.\n   *\n   * @param array $field\n   *   Contains the field values.\n   * @param RequestInterface $request\n   *   The request.\n   *\n   * @throws ServerConfigurationException\n   *   If the entity type is empty.\n   */\n  public function __construct(array $field, RequestInterface $request) {\n    if ($this->decorated) {\n      $this->setRequest($request);\n    }\n    if (empty($field['entityType'])) {\n      throw new ServerConfigurationException(sprintf('Unknown entity type for %s resource field.', __CLASS__));\n    }\n    $this->setEntityType($field['entityType']);\n    $this->wrapperMethod = isset($field['wrapper_method']) ? $field['wrapper_method'] : $this->wrapperMethod;\n    $this->subProperty = isset($field['sub_property']) ? $field['sub_property'] : $this->subProperty;\n    $this->formatter = isset($field['formatter']) ? $field['formatter'] : $this->formatter;\n    $this->wrapperMethodOnEntity = isset($field['wrapper_method_on_entity']) ? $field['wrapper_method_on_entity'] : $this->wrapperMethodOnEntity;\n    $this->column = isset($field['column']) ? $field['column'] : $this->column;\n    $this->imageStyles = isset($field['image_styles']) ? $field['image_styles'] : $this->imageStyles;\n    if (!empty($field['bundle'])) {\n      // TODO: Document this usage.\n      $this->setBundle($field['bundle']);\n    }\n\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create(array $field, RequestInterface $request = NULL, ResourceFieldInterface $decorated = NULL) {\n    $request = $request ?: restful()->getRequest();\n    $resource_field = NULL;\n    $class_name = static::fieldClassName($field);\n    // If the class exists and is a ResourceFieldEntityInterface use that one.\n    if (\n      $class_name &&\n      class_exists($class_name) &&\n      in_array(\n        'Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityInterface',\n        class_implements($class_name)\n      )\n    ) {\n      $resource_field = new $class_name($field, $request);\n    }\n\n    // If no specific class was found then use the current one.\n    if (!$resource_field) {\n      // Create the current object.\n      $resource_field = new static($field, $request);\n    }\n    if (!$resource_field) {\n      throw new ServerConfigurationException('Unable to create resource field');\n    }\n    // Set the basic object to the decorated property.\n    $resource_field->decorate($decorated ? $decorated : new ResourceField($field, $request));\n    $resource_field->decorated->addDefaults();\n\n    // Add the default specifics for the current object.\n    $resource_field->addDefaults();\n    return $resource_field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function value(DataInterpreterInterface $interpreter) {\n    $value = $this->decorated->value($interpreter);\n    if (isset($value)) {\n      // Let the decorated resolve callbacks.\n      return $value;\n    }\n\n    // Check user has access to the property.\n    if (!$this->access('view', $interpreter)) {\n      return NULL;\n    }\n\n    $property_wrapper = $this->propertyWrapper($interpreter);\n    $wrapper = $interpreter->getWrapper();\n\n    if ($property_wrapper instanceof \\EntityListWrapper) {\n      $values = array();\n      // Multiple values.\n      foreach ($property_wrapper->getIterator() as $item_wrapper) {\n        $values[] = $this->singleValue($item_wrapper, $wrapper, $interpreter->getAccount());\n      }\n      return $values;\n    }\n    return $this->singleValue($property_wrapper, $wrapper, $interpreter->getAccount());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function compoundDocumentId(DataInterpreterInterface $interpreter) {\n    $collections = $this->render($interpreter);\n    // Extract the document ID from the field resource collection.\n    $process = function ($collection) {\n      if (!$collection instanceof ResourceFieldCollectionInterface) {\n        return $collection;\n      }\n      $id_field = $collection->getIdField();\n      return $id_field->render($collection->getInterpreter());\n    };\n    // If cardinality is 1, then we don't have an array.\n    return $this->getCardinality() == 1 ?\n      $process($collections) :\n      array_map($process, array_filter($collections));\n  }\n\n  /**\n   * Helper function to get the identifier from a property wrapper.\n   *\n   * @param \\EntityMetadataWrapper $property_wrapper\n   *   The property wrapper to get the ID from.\n   *\n   * @return string\n   *   An identifier.\n   */\n  protected function propertyIdentifier(\\EntityMetadataWrapper $property_wrapper) {\n    if ($property_wrapper instanceof \\EntityDrupalWrapper) {\n      // The property wrapper is a reference to another entity get the entity\n      // ID.\n      $identifier = $this->referencedId($property_wrapper);\n      $resource = $this->getResource();\n      // TODO: Make sure we still want to support fullView.\n      if (!$resource || !$identifier || (isset($resource['fullView']) && $resource['fullView'] === FALSE)) {\n        return $identifier;\n      }\n      // If there is a resource that we are pointing to, we need to use the id\n      // field that that particular resource has in its configuration. Trying to\n      // load by the entity id in that scenario will lead to a 404.\n      // We'll load the plugin to get the idField configuration.\n      $instance_id = sprintf('%s:%d.%d', $resource['name'], $resource['majorVersion'], $resource['minorVersion']);\n      /* @var ResourceInterface $resource */\n      $resource = restful()\n        ->getResourceManager()\n        ->getPluginCopy($instance_id, Request::create('', array(), RequestInterface::METHOD_GET));\n      $plugin_definition = $resource->getPluginDefinition();\n      if (empty($plugin_definition['dataProvider']['idField'])) {\n        return $identifier;\n      }\n      try {\n        return $property_wrapper->{$plugin_definition['dataProvider']['idField']}->value();\n      }\n      catch (\\EntityMetadataWrapperException $e) {\n        return $identifier;\n      }\n    }\n    // The property is a regular one, get the value out of it and use it as\n    // the embedded identifier.\n    return $this->fieldValue($property_wrapper);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($value, DataInterpreterInterface $interpreter) {\n    try {\n      $property_wrapper = $interpreter->getWrapper()->{$this->getProperty()};\n      $property_wrapper->set($value);\n    }\n    catch (\\Exception $e) {\n      $this->decorated->set($value, $interpreter);\n    }\n  }\n\n  /**\n   * Returns the value for the current single field.\n   *\n   * This implementation will also add some metadata to the resource field\n   * object about the entity it is referencing.\n   *\n   * @param \\EntityMetadataWrapper $property_wrapper\n   *   The property wrapper. Either \\EntityDrupalWrapper or \\EntityListWrapper.\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The entity wrapper.\n   * @param object $account\n   *   The user account.\n   *\n   * @return mixed\n   *   A single value for the field.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\ServerConfigurationException\n   */\n  protected function singleValue(\\EntityMetadataWrapper $property_wrapper, \\EntityDrupalWrapper $wrapper, $account) {\n    if ($resource = $this->getResource()) {\n      // TODO: The resource input data in the field definition has changed.\n      // Now it does not need to be keyed by bundle since you don't even need\n      // an entity to use the resource based field.\n      $embedded_identifier = $this->propertyIdentifier($property_wrapper);\n      // Allow embedding entities with ID 0, like the anon user.\n      if (empty($embedded_identifier) && $embedded_identifier !== 0) {\n        return NULL;\n      }\n      if (isset($resource['fullView']) && $resource['fullView'] === FALSE) {\n        return $embedded_identifier;\n      }\n      // We support dot notation for the sparse fieldsets. That means that\n      // clients can specify the fields to show based on the \"fields\" query\n      // string parameter.\n      $parsed_input = array(\n        'fields' => implode(',', $this->nestedDottedChildren('fields')),\n        'include' => implode(',', $this->nestedDottedChildren('include')),\n        'filter' => $this->nestedDottedChildren('filter'),\n      );\n      $request = Request::create('', array_filter($parsed_input), RequestInterface::METHOD_GET);\n\n      // Get a plugin (that can be altered with decorators.\n      $embedded_resource = restful()->getResourceManager()->getPluginCopy(sprintf('%s:%d.%d', $resource['name'], $resource['majorVersion'], $resource['minorVersion']));\n      // Configure the plugin copy with the sub-request and sub-path.\n      $embedded_resource->setPath($embedded_identifier);\n      $embedded_resource->setRequest($request);\n      $embedded_resource->setAccount($account);\n      $metadata = $this->getMetadata($wrapper->getIdentifier());\n      $metadata = $metadata ?: array();\n      $metadata[] = $this->buildResourceMetadataItem($property_wrapper);\n      $this->addMetadata($wrapper->getIdentifier(), $metadata);\n      try {\n        // Get the contents to embed in place of the reference ID.\n        /* @var ResourceFieldCollection $embedded_entity */\n        $embedded_entity = $embedded_resource\n          ->getDataProvider()\n          ->view($embedded_identifier);\n      }\n      catch (InaccessibleRecordException $e) {\n        // If you don't have access to the embedded entity is like not having\n        // access to the property.\n        watchdog_exception('restful', $e);\n        return NULL;\n      }\n      catch (UnprocessableEntityException $e) {\n        // If you access a nonexistent embedded entity.\n        watchdog_exception('restful', $e);\n        return NULL;\n      }\n      // Test if the $embedded_entity meets the filter or not.\n      if (empty($parsed_input['filter'])) {\n        return $embedded_entity;\n      }\n      foreach ($parsed_input['filter'] as $filter) {\n        // Filters only apply if the target is the current field.\n        if (!empty($filter['target']) && $filter['target'] == $this->getPublicName() && !$embedded_entity->evalFilter($filter)) {\n          // This filter is not met.\n          return NULL;\n        }\n      }\n      return $embedded_entity;\n    }\n\n    if ($this->getFormatter()) {\n      // Get value from field formatter.\n      $value = $this->formatterValue($property_wrapper, $wrapper);\n    }\n    else {\n      // Single value.\n      $value = $this->fieldValue($property_wrapper);\n    }\n\n    return $value;\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * @throws \\EntityMetadataWrapperException\n   */\n  public function access($op, DataInterpreterInterface $interpreter) {\n    // Perform basic access checks.\n    if (!$this->decorated->access($op, $interpreter)) {\n      return FALSE;\n    }\n\n    if (!$this->getProperty()) {\n      // If there is no property we cannot check for property access.\n      return TRUE;\n    }\n\n    // Perform field API access checks.\n    if (!$property_wrapper = $this->propertyWrapper($interpreter)) {\n      return FALSE;\n    }\n    if ($this->isWrapperMethodOnEntity() && $this->getWrapperMethod() && $this->getProperty()) {\n      // Sometimes we define fields as $wrapper->getIdentifier. We need to\n      // resolve that to $wrapper->nid to call $wrapper->nid->info().\n      $property_wrapper = $property_wrapper->{$this->getProperty()};\n    }\n    $account = $interpreter->getAccount();\n\n    // Check format access for text fields.\n    if (\n      $op == 'edit' &&\n      $property_wrapper->type() == 'text_formatted' &&\n      $property_wrapper->value() &&\n      $property_wrapper->format->value()\n    ) {\n      $format = (object) array('format' => $property_wrapper->format->value());\n      // Only check filter access on write contexts.\n      if (!filter_access($format, $account)) {\n        return FALSE;\n      }\n    }\n\n    $info = $property_wrapper->info();\n    if ($op == 'edit' && empty($info['setter callback'])) {\n      // Property does not allow setting.\n      return FALSE;\n    }\n\n    // If $interpreter->getWrapper()->value() === FALSE it means that the entity\n    // could not be loaded, thus checking properties on it will result in\n    // errors.\n    // Ex: this happens when the embedded author is the anonymous user. Doing\n    // user_load(0) returns FALSE.\n    $access = $interpreter->getWrapper()\n        ->value() !== FALSE && $property_wrapper->access($op, $account);\n    return $access !== FALSE;\n  }\n\n  /**\n   * Get the wrapper for the property associated to the current field.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data source.\n   *\n   * @return \\EntityMetadataWrapper\n   *   Either a \\EntityStructureWrapper or a \\EntityListWrapper.\n   *\n   * @throws ServerConfigurationException\n   */\n  protected function propertyWrapper(DataInterpreterInterface $interpreter) {\n    // This is the first method that gets called for all fields after loading\n    // the entity. We'll use that opportunity to set the actual bundle of the\n    // field.\n    $this->setBundle($interpreter->getWrapper()->getBundle());\n\n    // Exposing an entity field.\n    $wrapper = $interpreter->getWrapper();\n    // For entity fields the DataInterpreter needs to contain an EMW.\n    if (!$wrapper instanceof \\EntityDrupalWrapper) {\n      throw new ServerConfigurationException('Cannot get a value without an entity metadata wrapper data source.');\n    }\n    $property = $this->getProperty();\n    try {\n      return ($property && !$this->isWrapperMethodOnEntity()) ? $wrapper->{$property} : $wrapper;\n    }\n    catch (\\EntityMetadataWrapperException $e) {\n      throw new UnprocessableEntityException(sprintf('The property %s could not be found in %s:%s.', $property, $wrapper->type(), $wrapper->getBundle()));\n    }\n  }\n\n  /**\n   * Get value from a property.\n   *\n   * @param \\EntityMetadataWrapper $property_wrapper\n   *   The property wrapper. Either \\EntityDrupalWrapper or \\EntityListWrapper.\n   *\n   * @return mixed\n   *   A single or multiple values.\n   */\n  protected function fieldValue(\\EntityMetadataWrapper $property_wrapper) {\n    if ($this->getSubProperty() && $property_wrapper->value()) {\n      $property_wrapper = $property_wrapper->{$this->getSubProperty()};\n    }\n\n    // Wrapper method.\n    return $property_wrapper->{$this->getWrapperMethod()}();\n  }\n\n  /**\n   * Get value from a field rendered by Drupal field API's formatter.\n   *\n   * @param \\EntityMetadataWrapper $property_wrapper\n   *   The property wrapper. Either \\EntityDrupalWrapper or \\EntityListWrapper.\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The entity wrapper.\n   *\n   * @return mixed\n   *   A single or multiple values.\n   *\n   * @throws \\Drupal\\restful\\Exception\\ServerConfigurationException\n   */\n  protected function formatterValue(\\EntityMetadataWrapper $property_wrapper, \\EntityDrupalWrapper $wrapper) {\n    $value = NULL;\n\n    if (!ResourceFieldEntity::propertyIsField($this->getProperty())) {\n      // Property is not a field.\n      throw new ServerConfigurationException(format_string('@property is not a configurable field, so it cannot be processed using field API formatter', array('@property' => $this->getProperty())));\n    }\n\n    // Get values from the formatter.\n    $output = field_view_field($this->getEntityType(), $wrapper->value(), $this->getProperty(), $this->getFormatter());\n\n    // Unset the theme, as we just want to get the value from the formatter,\n    // without the wrapping HTML.\n    unset($output['#theme']);\n\n\n    if ($property_wrapper instanceof \\EntityListWrapper) {\n      // Multiple values.\n      foreach (element_children($output) as $delta) {\n        $value[] = drupal_render($output[$delta]);\n      }\n    }\n    else {\n      // Single value.\n      $value = drupal_render($output);\n    }\n\n    return $value;\n  }\n\n  /**\n   * Get the children of a query string parameter that apply to the field.\n   *\n   * For instance: if the field is 'relatedArticles' and the query string is\n   * '?relatedArticles.one.two,articles' it returns array('one.two').\n   *\n   * @param string $key\n   *   The name of the key: include|fields\n   *\n   * @return string[]\n   *   The list of fields.\n   */\n  protected function nestedDottedChildren($key) {\n    // Filters are dealt with differently.\n    if ($key == 'filter') {\n      return $this->nestedDottedFilters();\n    }\n    $allowed_values = array('include', 'fields');\n    if (!in_array($key, $allowed_values)) {\n      return array();\n    }\n    $input = $this\n      ->getRequest()\n      ->getParsedInput();\n    $limit_values = !empty($input[$key]) ? explode(',', $input[$key]) : array();\n    $limit_values = array_filter($limit_values, function ($value) {\n      $parts = explode('.', $value);\n      return $parts[0] == $this->getPublicName() && $value != $this->getPublicName();\n    });\n    return array_map(function ($value) {\n      return substr($value, strlen($this->getPublicName()) + 1);\n    }, $limit_values);\n  }\n\n  /**\n   * Process the filter query string for the relevant sub-query.\n   *\n   * Selects the filters that start with the field name.\n   *\n   * @return array\n   *   The processed filters.\n   */\n  protected function nestedDottedFilters() {\n    $input = $this\n      ->getRequest()\n      ->getParsedInput();\n    if (empty($input['filter'])) {\n      return array();\n    }\n    $output_filters = array();\n    $filters = $input['filter'];\n    foreach ($filters as $filter_public_name => $filter) {\n      $filter = DataProvider::processFilterInput($filter, $filter_public_name);\n      if (strpos($filter_public_name, $this->getPublicName() . '.') === 0) {\n        // Remove the prefix and add it to the filters for the next request.\n        $new_name = substr($filter_public_name, strlen($this->getPublicName()) + 1);\n        $filter['public_field'] = $new_name;\n        $output_filters[$new_name] = $filter;\n      }\n    }\n    return $output_filters;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addMetadata($key, $value) {\n    $this->decorated->addMetadata($key, $value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMetadata($key) {\n    return $this->decorated->getMetadata($key);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function executeProcessCallbacks($value) {\n    return $this->decorated->executeProcessCallbacks($value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(DataInterpreterInterface $interpreter) {\n    return $this->executeProcessCallbacks($this->value($interpreter));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDefinition() {\n    return $this->decorated->getDefinition();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPublicFieldInfo() {\n    return $this->decorated->getPublicFieldInfo();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPublicFieldInfo(PublicFieldInfoInterface $public_field_info) {\n    $this->decorated->setPublicFieldInfo($public_field_info);\n  }\n\n  /**\n   * Get value for a field based on another resource.\n   *\n   * @param DataInterpreterInterface $source\n   *   The data source.\n   *\n   * @return mixed\n   *   A single or multiple values.\n   */\n  protected function resourceValue(DataInterpreterInterface $source) {}\n\n  /**\n   * {@inheritdoc}\n   */\n  public function decorate(ResourceFieldInterface $decorated) {\n    $this->decorated = $decorated;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getSubProperty() {\n    return $this->subProperty;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setSubProperty($sub_property) {\n    $this->subProperty = $sub_property;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFormatter() {\n    return $this->formatter;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setFormatter($formatter) {\n    $this->formatter = $formatter;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getWrapperMethod() {\n    return $this->wrapperMethod;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setWrapperMethod($wrapper_method) {\n    $this->wrapperMethod = $wrapper_method;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isWrapperMethodOnEntity() {\n    return $this->wrapperMethodOnEntity;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setWrapperMethodOnEntity($wrapper_method_on_entity) {\n    $this->wrapperMethodOnEntity = $wrapper_method_on_entity;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getColumn() {\n    if (isset($this->column)) {\n      return $this->column;\n    }\n    if ($this->getProperty() && $field = $this::fieldInfoField($this->getProperty())) {\n      if ($field['type'] == 'text_long') {\n        // Do not default to format.\n        $this->setColumn('value');\n      }\n      else {\n        // Set the column name.\n        $this->setColumn(key($field['columns']));\n      }\n    }\n    return $this->column;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setColumn($column) {\n    $this->column = $column;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getImageStyles() {\n    return $this->imageStyles;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setImageStyles($image_styles) {\n    $this->imageStyles = $image_styles;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getEntityType() {\n    return $this->entityType;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setEntityType($entity_type) {\n    $this->entityType = $entity_type;\n  }\n\n  /**\n   * Gets the \\EntityStructureWrapper for the entity type.\n   *\n   * @return mixed\n   *   The \\EntityStructureWrapper if the entity type exists.\n   */\n  protected function entityTypeWrapper() {\n    static $entity_wrappers = array();\n    $key = sprintf('%s:%s', $this->getEntityType(), $this->getBundle());\n    if (isset($entity_wrappers[$key])) {\n      return $entity_wrappers[$key];\n    }\n    $entity_wrappers[$key] = entity_metadata_wrapper($this->getEntityType(), NULL, array(\n      'bundle' => $this->getBundle(),\n    ));\n    return $entity_wrappers[$key];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getBundle() {\n    return $this->bundle;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setBundle($bundle) {\n    // Do not do pointless work if not needed.\n    if (!empty($this->bundle) && $this->bundle == $bundle) {\n      return;\n    }\n    $this->bundle = $bundle;\n\n    // If this is an options call, then introspect Entity API to add more data\n    // to the public field information.\n    if ($this->getRequest()->getMethod() == RequestInterface::METHOD_OPTIONS) {\n      $this->populatePublicInfoField();\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * Almost all the defaults come are applied by the object's property defaults.\n   */\n  public function addDefaults() {\n    // Set the defaults from the decorated.\n    $this->setResource($this->decorated->getResource());\n\n    // If entity metadata wrapper methods were used, then return the appropriate\n    // entity property.\n    if ($this->isWrapperMethodOnEntity() && $this->getWrapperMethod()) {\n      $this->propertyOnEntity();\n    }\n\n    // Set the Entity related defaults.\n    if (\n      ($this->property = $this->decorated->getProperty()) &&\n      ($field = $this::fieldInfoField($this->property)) &&\n      $field['type'] == 'image' &&\n      ($image_styles = $this->getImageStyles())\n    ) {\n      // If it's an image check if we need to add image style processing.\n      $process_callbacks = $this->getProcessCallbacks();\n      array_unshift($process_callbacks, array(\n        array($this, 'getImageUris'),\n        array($image_styles),\n      ));\n      $this->setProcessCallbacks($process_callbacks);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getImageUris(array $file_array, $image_styles) {\n    // Return early if there are no image styles.\n    if (empty($image_styles)) {\n      return $file_array;\n    }\n    // If $file_array is an array of file arrays. Then call recursively for each\n    // item and return the result.\n    if (static::isArrayNumeric($file_array)) {\n      $output = array();\n      foreach ($file_array as $item) {\n        $output[] = static::getImageUris($item, $image_styles);\n      }\n      return $output;\n    }\n    $file_array['image_styles'] = array();\n    foreach ($image_styles as $style) {\n      $file_array['image_styles'][$style] = image_style_url($style, $file_array['uri']);\n    }\n    return $file_array;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function propertyIsField($name) {\n    return (bool) static::fieldInfoField($name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function preprocess($value) {\n    // By default assume that there is no preprocess and allow extending classes\n    // to implement this.\n    return $value;\n  }\n\n  /**\n   * Get the class name to use based on the field definition.\n   *\n   * @param array $field_definition\n   *   The processed field definition with the user values.\n   *\n   * @return string\n   *   The class name to use. If the class name is empty or does not implement\n   *   ResourceFieldInterface then ResourceField will be used. NULL if nothing\n   *   was found.\n   */\n  public static function fieldClassName(array $field_definition) {\n    if (!empty($field_definition['class']) && $field_definition['class'] != '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntity') {\n      // If there is a class that is not the current, return it.\n      return $field_definition['class'];\n    }\n    // If there is an extending class for the particular field use that class\n    // instead.\n    if (empty($field_definition['property']) || !$field_info = static::fieldInfoField($field_definition['property'])) {\n      return NULL;\n    }\n\n    switch ($field_info['type']) {\n      case 'entityreference':\n      case 'taxonomy_term_reference':\n        return '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityReference';\n\n      case 'text':\n      case 'text_long':\n      case 'text_with_summary':\n        return '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityText';\n\n      case 'file':\n      case 'image':\n        // If the field is treated as a resource, then default to the reference.\n        if (!empty($field_definition['resource'])) {\n          return '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldFileEntityReference';\n        }\n        return '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityFile';\n\n      default:\n        return NULL;\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPublicName() {\n    return $this->decorated->getPublicName();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPublicName($public_name) {\n    $this->decorated->setPublicName($public_name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccessCallbacks() {\n    return $this->decorated->getAccessCallbacks();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccessCallbacks($access_callbacks) {\n    $this->decorated->setAccessCallbacks($access_callbacks);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProperty() {\n    return $this->property;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProperty($property) {\n    $this->property = $property;\n    $this->decorated->setProperty($property);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCallback() {\n    return $this->decorated->getCallback();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCallback($callback) {\n    $this->decorated->setCallback($callback);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProcessCallbacks() {\n    return $this->decorated->getProcessCallbacks();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProcessCallbacks($process_callbacks) {\n    $this->decorated->setProcessCallbacks($process_callbacks);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResource() {\n    return $this->decorated->getResource();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResource($resource) {\n    $this->decorated->setResource($resource);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMethods() {\n    return $this->decorated->getMethods();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setMethods($methods) {\n    $this->decorated->setMethods($methods);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function id() {\n    return $this->decorated->id();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isComputed() {\n    return $this->decorated->isComputed();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function autoDiscovery() {\n    if (method_exists($this->decorated, 'autoDiscovery')) {\n      return $this->decorated->autoDiscovery();\n    }\n    return ResourceFieldBase::emptyDiscoveryInfo($this->getPublicName());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCardinality() {\n    if (isset($this->cardinality)) {\n      return $this->cardinality;\n    }\n    // Default to single cardinality.\n    $this->cardinality = 1;\n    if ($field_info = $this::fieldInfoField($this->getProperty())) {\n      $this->cardinality = empty($field_info['cardinality']) ? $this->cardinality : $field_info['cardinality'];\n    }\n    return $this->cardinality;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCardinality($cardinality) {\n    $this->cardinality = $cardinality;\n  }\n\n  /**\n   * Helper method to determine if an array is numeric.\n   *\n   * @param array $input\n   *   The input array.\n   *\n   * @return bool\n   *   TRUE if the array is numeric, false otherwise.\n   */\n  public static function isArrayNumeric(array $input) {\n    return ResourceFieldBase::isArrayNumeric($input);\n  }\n\n  /**\n   * Builds a metadata item for a field value.\n   *\n   * It will add information about the referenced entity. NOTE: Do not type hint\n   * the $wrapper argument to avoid PHP errors for the file entities. Those are\n   * no true entity references, but file arrays (although they reference file\n   * entities)\n   *\n   * @param \\EntityDrupalWrapper $wrapper\n   *   The wrapper to the referenced entity.\n   *\n   * @return array\n   *   The metadata array item.\n   */\n  protected function buildResourceMetadataItem($wrapper) {\n    if ($wrapper instanceof \\EntityValueWrapper) {\n      $wrapper = entity_metadata_wrapper($this->getEntityType(), $wrapper->value());\n    }\n    $id = $wrapper->getIdentifier();\n    $bundle = $wrapper->getBundle();\n    $resource = $this->getResource();\n    return array(\n      'id' => $id,\n      'entity_type' => $wrapper->type(),\n      'bundle' => $bundle,\n      'resource_name' => $resource['name'],\n    );\n  }\n\n  /**\n   * Helper function to get the referenced entity ID.\n   *\n   * @param \\EntityDrupalWrapper $property_wrapper\n   *   The wrapper for the referenced file array.\n   *\n   * @return mixed\n   *   The ID.\n   */\n  protected function referencedId($property_wrapper) {\n    return $property_wrapper->getIdentifier() ?: NULL;\n  }\n\n  /**\n   * Sets the resource field property to the schema field in the entity.\n   *\n   * @throws \\EntityMetadataWrapperException\n   */\n  protected function propertyOnEntity() {\n    // If there is no property try to get it based on the wrapper method and\n    // store the value in the decorated object.\n    $property = NULL;\n\n    $wrapper_method = $this->getWrapperMethod();\n    $wrapper = $this->entityTypeWrapper();\n    if ($wrapper_method == 'label') {\n      // Store the label key.\n      $property = $wrapper->entityKey('label');\n    }\n    elseif ($wrapper_method == 'getBundle') {\n      // Store the bundle key.\n      $property = $wrapper->entityKey('bundle');\n    }\n    elseif ($wrapper_method == 'getIdentifier') {\n      // Store the ID key.\n      $property = $wrapper->entityKey('id');\n    }\n\n    // There are occasions when the wrapper property is not the schema\n    // database field.\n    if (!is_a($wrapper, '\\EntityStructureWrapper')) {\n      // The entity type does not exist.\n      return;\n    }\n\n    /* @var $wrapper \\EntityStructureWrapper */\n    foreach ($wrapper->getPropertyInfo() as $wrapper_property => $property_info) {\n      if (!empty($property_info['schema field']) && $property_info['schema field'] == $property) {\n        $property = $wrapper_property;\n        break;\n      }\n    }\n\n    $this->setProperty($property);\n  }\n\n  /**\n   * Populate public info field with Property API information.\n   */\n  protected function populatePublicInfoField() {\n    $field_definition = $this->getDefinition();\n    $discovery_info = empty($field_definition['discovery']) ? array() : $field_definition['discovery'];\n    $public_field_info = new PublicFieldInfoEntity(\n      $this->getPublicName(),\n      $this->getProperty(),\n      $this->getEntityType(),\n      $this->getBundle(),\n      $discovery_info\n    );\n    $this->setPublicFieldInfo($public_field_info);\n\n    if ($field_instance = field_info_instance($this->getEntityType(), $this->getProperty(), $this->getBundle())) {\n      $public_field_info->addSectionDefaults('info', array(\n        'label' => $field_instance['label'],\n        'description' => $field_instance['description'],\n      ));\n      $field_info = $this::fieldInfoField($this->getProperty());\n      $section_info = array();\n      $section_info['label'] = empty($field_info['label']) ? NULL : $field_info['label'];\n      $section_info['description'] = empty($field_info['description']) ? NULL : $field_info['description'];\n      $public_field_info->addSectionDefaults('info', $section_info);\n      $type = $public_field_info instanceof PublicFieldInfoEntityInterface ? $public_field_info->getFormSchemaAllowedType() : NULL;\n      $public_field_info->addSectionDefaults('form_element', array(\n        'default_value' => isset($field_instance['default_value']) ? $field_instance['default_value'] : NULL,\n        'type' => $type,\n      ));\n      // Loading allowed values can be a performance issue, load them only if\n      // they are not provided in the field definition.\n      $form_element_info = $public_field_info->getSection('form_element');\n      if (!isset($form_element_info['allowed_values'])) {\n        $allowed_values = $public_field_info instanceof PublicFieldInfoEntityInterface ? $public_field_info->getFormSchemaAllowedValues() : NULL;\n        $public_field_info->addSectionDefaults('form_element', array(\n          'allowed_values' => $allowed_values,\n        ));\n      }\n    }\n    else {\n      // Extract the discovery information from the property info.\n      try {\n        $property_info = $this\n          ->entityTypeWrapper()\n          ->getPropertyInfo($this->getProperty());\n      }\n      catch(\\EntityMetadataWrapperException $e) {\n        return;\n      }\n      if (empty($property_info)) {\n        return;\n      }\n      $public_field_info->addSectionDefaults('data', array(\n        'type' => $property_info['type'],\n        'required' => empty($property_info['required']) ? FALSE : $property_info['required'],\n      ));\n      $public_field_info->addSectionDefaults('info', array(\n        'label' => $property_info['label'],\n        'description' => $property_info['description'],\n      ));\n    }\n  }\n\n  /**\n   * Gets statically cached information about a field.\n   *\n   * @param string $field_name\n   *   The name of the field to retrieve. $field_name can only refer to a\n   *   non-deleted, active field. For deleted fields, use\n   *   field_info_field_by_id(). To retrieve information about inactive fields,\n   *   use field_read_fields().\n   *\n   * @return array\n   *   The field info.\n   *\n   * @see field_info_field()\n   */\n  protected static function fieldInfoField($field_name) {\n    return field_info_field($field_name);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntityAlterableInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldFilterableInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\n/**\n * Class ResourceFieldFilterableInterface.\n *\n * @package Drupal\\restful\\Plugin\\resource\\Field\n */\ninterface ResourceFieldEntityAlterableInterface {\n\n  /**\n   * Alter the list query to add the filtering for this field.\n   *\n   * @param array $filter\n   *   The filter array definition.\n   * @param \\EntityFieldQuery $query\n   *   The entity field query to modify.\n   *\n   * @return array\n   *   The modified $filter array.\n   */\n  public function alterFilterEntityFieldQuery(array $filter, \\EntityFieldQuery $query);\n\n  /**\n   * Alter the list query to add the sorting for this field.\n   *\n   * @param array $sort\n   *   The sort array definition.\n   * @param \\EntityFieldQuery $query\n   *   The entity field query to modify.\n   *\n   * @return array\n   *   The modified $sort array.\n   */\n  public function alterSortEntityFieldQuery(array $sort, \\EntityFieldQuery $query);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntityFile.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityFile\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass ResourceFieldEntityFile extends ResourceFieldEntity implements ResourceFieldEntityInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function preprocess($value) {\n    $field_info = field_info_field($this->getProperty());\n    if ($field_info['cardinality'] == 1) {\n      // Single value.\n      return array(\n        'fid' => $value,\n        'display' => TRUE,\n      );\n    }\n\n    $value = is_array($value) ? $value : explode(',', $value);\n    $return = array();\n    foreach ($value as $delta => $single_value) {\n      $return[$delta] = array(\n        'fid' => $single_value,\n        'display' => TRUE,\n      );\n    }\n    return $return;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function executeProcessCallbacks($value) {\n    return $this->decorated->executeProcessCallbacks($value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDefinition() {\n    return $this->decorated->getDefinition();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntityInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\ninterface ResourceFieldEntityInterface extends ResourceFieldInterface {\n\n  /**\n   * Decorate the object.\n   *\n   * @param ResourceFieldInterface $decorated\n   *   The decorated subject.\n   */\n  public function decorate(ResourceFieldInterface $decorated);\n\n  /**\n   * @return string\n   */\n  public function getSubProperty();\n\n  /**\n   * @param string $sub_property\n   */\n  public function setSubProperty($sub_property);\n\n  /**\n   * @return string\n   */\n  public function getFormatter();\n\n  /**\n   * @param array $formatter\n   */\n  public function setFormatter($formatter);\n\n  /**\n   * @return string\n   */\n  public function getWrapperMethod();\n\n  /**\n   * @param string $wrapper_method\n   */\n  public function setWrapperMethod($wrapper_method);\n\n  /**\n   * @return boolean\n   */\n  public function isWrapperMethodOnEntity();\n\n  /**\n   * @param boolean $wrapper_method_on_entity\n   */\n  public function setWrapperMethodOnEntity($wrapper_method_on_entity);\n\n  /**\n   * @return string\n   */\n  public function getColumn();\n\n  /**\n   * @param string $column\n   */\n  public function setColumn($column);\n\n  /**\n   * @return array\n   */\n  public function getImageStyles();\n\n  /**\n   * @param array $image_styles\n   */\n  public function setImageStyles($image_styles);\n\n  /**\n   * @return string\n   */\n  public function getEntityType();\n\n  /**\n   * @param string $entity_type\n   */\n  public function setEntityType($entity_type);\n\n  /**\n   * @return string\n   */\n  public function getBundle();\n\n  /**\n   * @param string $bundle\n   */\n  public function setBundle($bundle);\n  /**\n   * Get the image URLs based on the configured image styles.\n   *\n   * @param array $file_array\n   *   The file array.\n   * @param array $image_styles\n   *   The list of image styles to use.\n   *\n   * @return array\n   *   The input file array with an extra key for the image styles.\n   */\n  public static function getImageUris(array $file_array, $image_styles);\n\n  /**\n   * Checks if a given string represents a Field API field.\n   *\n   * @param string $name\n   *   The name of the field/property.\n   *\n   * @return bool\n   *   TRUE if it's a field. FALSE otherwise.\n   */\n  public static function propertyIsField($name);\n\n  /**\n   * Massage the value to set according to the format expected by the wrapper.\n   *\n   * @param mixed $value\n   *   The value passed in the request.\n   *\n   * @return mixed\n   *   The value to set using the wrapped property.\n   */\n  public function preprocess($value);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntityReference.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityReference.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Http\\HttpHeaderBag;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderResource;\n\n/**\n * Class ResourceFieldEntityReference.\n *\n * @package Drupal\\restful\\Plugin\\resource\\Field\n */\nclass ResourceFieldEntityReference extends ResourceFieldEntity implements ResourceFieldEntityReferenceInterface {\n\n  /**\n   * Property where the ID should be retrieved from.\n   *\n   * If empty, the entity ID will be used. It's either the property or Field API\n   * field name.\n   *\n   * @var string\n   */\n  protected $referencedIdProperty;\n\n  /**\n   * Constructs a ResourceFieldEntityReference.\n   *\n   * @param array $field\n   *   Contains the field values.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   */\n  public function __construct(array $field, RequestInterface $request) {\n    parent::__construct($field, $request);\n    if (!empty($field['referencedIdProperty'])) {\n      $this->referencedIdProperty = $field['referencedIdProperty'];\n    }\n    // TODO: Document referencedIdProperty.\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function preprocess($value) {\n    if (!$value) {\n      // If value is empty, return NULL, so no new entity will be created.\n      return NULL;\n    }\n\n    $cardinality = $this->getCardinality();\n    if ($cardinality != 1 && !is_array($value)) {\n      // If the field is entity reference type and its cardinality larger than\n      // 1 set value to an array.\n      $value = explode(',', $value);\n    }\n\n    if ($cardinality != 1 && ResourceFieldBase::isArrayNumeric($value)) {\n      // Set the cardinality to 1 to process each value as a single value item.\n      $this->setCardinality(1);\n      // For multiple value items, pre-process them separately.\n      $values = array();\n      foreach ($value as $item) {\n        $values[] = $this->preprocess($item);\n      }\n      $this->setCardinality($cardinality);\n      return $values;\n    }\n    // If the provided value is the ID to the referenced entity, then do not do\n    // a sub-request.\n    if (!is_array($value) || empty($value['body'])) {\n      // Allow to pass an array with the ID instead of the ID directly.\n      return (!empty($value['id']) && array_keys($value) == array('id')) ? $value['id'] : $value;\n    }\n\n    /* @var ResourceFieldCollectionInterface $merged_value */\n    $merged_value = $this->mergeEntityFromReference($value);\n    return $merged_value->getInterpreter()->getWrapper()->getIdentifier();\n  }\n\n  /**\n   * Helper function; Create an entity from a a sub-resource.\n   *\n   * @param mixed $value\n   *   The single value for the sub-request.\n   *\n   * @return mixed\n   *   The value to set using the wrapped property.\n   */\n  protected function mergeEntityFromReference($value) {\n    $resource = $this->getResource();\n    if (empty($resource) || empty($value['body'])) {\n      // Field is not defined as \"resource\", which means it only accepts an\n      // integer as a valid value.\n      // Or, we are passing an integer and cardinality is 1. That means that we\n      // are passing the ID of the referenced entity. Hence setting the new\n      // value to the reference field.\n      return $value;\n    }\n\n    // Get the resource data provider and make the appropriate operations.\n    // We need to create a RequestInterface object for the sub-request.\n    $resource_data_provider = DataProviderResource::init(static::subRequest($value), $resource['name'], array(\n      $resource['majorVersion'],\n      $resource['minorVersion'],\n    ));\n\n    // We are always dealing with the single value.\n    $merged = $resource_data_provider->merge(static::subRequestId($value), $value['body']);\n    return reset($merged);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function subRequest(array $value) {\n    if (empty($value['request'])) {\n      throw new BadRequestException('Malformed body payload. Missing \"request\" key for the sub-request.');\n    }\n    if (empty($value['request']['method'])) {\n      throw new BadRequestException('Malformed body payload. Missing \"method\" int the \"request\" key for the sub-request.');\n    }\n    $request_user_info = $value['request'] + array(\n      'path' => NULL,\n      'query' => array(),\n      'csrf_token' => NULL,\n    );\n\n    $headers = empty($request_user_info['headers']) ? array() : $request_user_info['headers'];\n    $request_user_info['headers'] = new HttpHeaderBag($headers);\n    $request_user_info['via_router'] = FALSE;\n    $request_user_info['cookies'] = $_COOKIE;\n    $request_user_info['files'] = $_FILES;\n    $request_user_info['server'] = $_SERVER;\n\n    return Request::create(\n      $request_user_info['path'],\n      $request_user_info['query'],\n      $request_user_info['method'],\n      $request_user_info['headers'],\n      $request_user_info['via_router'],\n      $request_user_info['csrf_token'],\n      $request_user_info['cookies'],\n      $request_user_info['files'],\n      $request_user_info['server']\n    );\n  }\n\n  /**\n   * Get the ID of the resource this write sub-request is for.\n   *\n   * @param array $value\n   *   The value provided for this sub-request item.\n   *\n   * @return string\n   *   The ID.\n   */\n  protected static function subRequestId($value) {\n    if ($value['request']['method'] == RequestInterface::METHOD_POST) {\n      // If the request is for post, then disregard any possible ID.\n      return NULL;\n    }\n    return empty($value['id']) ? NULL : $value['id'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function value(DataInterpreterInterface $interpreter) {\n    $value = $this->decorated->value($interpreter);\n    if (isset($value)) {\n      // Let the decorated resolve callbacks.\n      return $value;\n    }\n\n    // Check user has access to the property.\n    if (!$this->access('view', $interpreter)) {\n      return NULL;\n    }\n\n    $resource = $this->getResource();\n    // If the field definition does not contain a resource, or it is set\n    // explicitly to fullView FALSE, then return only the entity ID.\n    if (\n      $resource ||\n      (!empty($resource) && $resource['fullView'] !== FALSE) ||\n      $this->getFormatter()\n    ) {\n      // Let the resource embedding to the parent class.\n      return parent::value($interpreter);\n    }\n\n    // Since this is a reference field (a field that points to other entities,\n    // we can know for sure that the property wrappers are instances of\n    // \\EntityDrupalWrapper or lists of them.\n    $property_wrapper = $this->propertyWrapper($interpreter);\n    if (!$property_wrapper->value()) {\n      // If there is no referenced entity, return.\n      return NULL;\n    }\n\n    // If this is a multivalue field, then call recursively on the items.\n    if ($property_wrapper instanceof \\EntityListWrapper) {\n      $values = array();\n      foreach ($property_wrapper->getIterator() as $item_wrapper) {\n        $values[] = $this->referencedId($item_wrapper);\n      }\n      return $values;\n    }\n    /* @var $property_wrapper \\EntityDrupalWrapper */\n    return $this->referencedId($property_wrapper);\n  }\n\n  /**\n   * Helper function to get the referenced entity ID.\n   *\n   * @param \\EntityDrupalWrapper $property_wrapper\n   *   The wrapper for the referenced entity.\n   *\n   * @return mixed\n   *   The ID.\n   */\n  protected function referencedId($property_wrapper) {\n    $identifier = $property_wrapper->getIdentifier();\n    if (!$this->referencedIdProperty) {\n      return $identifier;\n    }\n    try {\n      return $identifier ? $property_wrapper->{$this->referencedIdProperty}->value() : NULL;\n    }\n    catch (\\EntityMetadataWrapperException $e) {\n      // An exception will be raised for broken entity reference fields.\n      return NULL;\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDefinition() {\n    return $this->decorated->getDefinition();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntityReferenceInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityReferenceInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\ninterface ResourceFieldEntityReferenceInterface extends ResourceFieldEntityInterface {\n\n  /**\n   * Creates a request object for the sub-request.\n   *\n   * @param array $value\n   *   An associative array containing the values to set in the nested call, and\n   *   information about how to create the request object.\n   *\n   * @return RequestInterface\n   *   The request object.\n   */\n  public static function subRequest(array $value);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldEntityText.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityText.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\nclass ResourceFieldEntityText extends ResourceFieldEntity implements ResourceFieldEntityInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function preprocess($value) {\n    // Text field. Check if field has an input format.\n\n    $field_info = field_info_field($this->getProperty());\n    // If there was no bundle that had the field instance, then return NULL.\n    if (!$instance = field_info_instance($this->getEntityType(), $this->getProperty(), $this->getBundle())) {\n      return NULL;\n    }\n\n    $return = NULL;\n    if ($field_info['cardinality'] == 1) {\n      // Single value.\n      if (!$instance['settings']['text_processing']) {\n        return $value;\n      }\n\n      return array(\n        'value' => $value,\n        // TODO: This is hardcoded! Fix it.\n        'format' => 'filtered_html',\n      );\n    }\n\n    // Multiple values.\n    foreach ($value as $delta => $single_value) {\n      if (!$instance['settings']['text_processing']) {\n        $return[$delta] = $single_value;\n      }\n      else {\n        $return[$delta] = array(\n          'value' => $single_value,\n          'format' => 'filtered_html',\n        );\n      }\n    }\n    return $return;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function executeProcessCallbacks($value) {\n    return $this->decorated->executeProcessCallbacks($value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDefinition() {\n    return $this->decorated->getDefinition();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldFileEntityReference.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldFileEntityReference.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\ResourcePluginManager;\n\nclass ResourceFieldFileEntityReference extends ResourceFieldEntityReference implements ResourceFieldEntityReferenceInterface {\n\n  // TODO: Add testing to this!\n  /**\n   * Helper function to get the identifier from a property wrapper.\n   *\n   * @param \\EntityMetadataWrapper $property_wrapper\n   *   The property wrapper to get the ID from.\n   *\n   * @return string\n   *   An identifier.\n   */\n  protected function propertyIdentifier(\\EntityMetadataWrapper $property_wrapper) {\n    // The property wrapper is a reference to another entity get the entity\n    // ID.\n    $file_array = $property_wrapper->value();\n    $identifier = $file_array['fid'];\n    $resource = $this->getResource();\n    // TODO: Make sure we still want to support fullView.\n    if (!$resource || !$identifier || (isset($resource['fullView']) && $resource['fullView'] === FALSE)) {\n      return $identifier;\n    }\n    // If there is a resource that we are pointing to, we need to use the id\n    // field that that particular resource has in its configuration. Trying to\n    // load by the entity id in that scenario will lead to a 404.\n    // We'll load the plugin to get the idField configuration.\n    $instance_id = sprintf('%s:%d.%d', $resource['name'], $resource['majorVersion'], $resource['minorVersion']);\n    /* @var ResourceInterface $resource */\n    $resource = restful()\n      ->getResourceManager()\n      ->getPluginCopy($instance_id, Request::create('', array(), RequestInterface::METHOD_GET));\n    $plugin_definition = $resource->getPluginDefinition();\n    if (empty($plugin_definition['dataProvider']['idField'])) {\n      return $identifier;\n    }\n    try {\n      $file_wrapper = entity_metadata_wrapper('file', $file_array['fid']);\n      return $file_wrapper->{$plugin_definition['dataProvider']['idField']}->value();\n    }\n    catch (\\EntityMetadataWrapperException $e) {\n      return $identifier;\n    }\n  }\n\n  /**\n   * Builds a metadata item for a field value.\n   *\n   * It will add information about the referenced entity.\n   *\n   * @param \\EntityMetadataWrapper $wrapper\n   *   The wrapper for the referenced file array.\n   *\n   * @return array\n   *   The metadata array item.\n   */\n  protected function buildResourceMetadataItem($wrapper) {\n    $file_array = $wrapper->value();\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper('file', $file_array['fid']);\n    return parent::buildResourceMetadataItem($wrapper);\n  }\n\n  /**\n   * Helper function to get the referenced entity ID.\n   *\n   * @param \\EntityStructureWrapper $property_wrapper\n   *   The wrapper for the referenced file array.\n   *\n   * @return mixed\n   *   The ID.\n   */\n  protected function referencedId($property_wrapper) {\n    $file_array = $property_wrapper->value();\n    if (!$this->referencedIdProperty) {\n      return $file_array['fid'];\n    }\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper('file', $file_array['fid']);\n    return $wrapper->{$this->referencedIdProperty}->value();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\IncompatibleFieldDefinitionException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoInterface;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\ninterface ResourceFieldInterface {\n\n  /**\n   * @return mixed\n   */\n  public function getPublicName();\n\n  /**\n   * @param mixed $public_name\n   */\n  public function setPublicName($public_name);\n\n  /**\n   * @return array\n   */\n  public function getAccessCallbacks();\n\n  /**\n   * @param array $access_callbacks\n   */\n  public function setAccessCallbacks($access_callbacks);\n\n  /**\n   * @return string\n   */\n  public function getProperty();\n\n  /**\n   * @param string $property\n   */\n  public function setProperty($property);\n\n  /**\n   * @return mixed\n   */\n  public function getCallback();\n\n  /**\n   * @param mixed $callback\n   */\n  public function setCallback($callback);\n\n  /**\n   * @return array\n   */\n  public function getProcessCallbacks();\n\n  /**\n   * @param array $process_callbacks\n   */\n  public function setProcessCallbacks($process_callbacks);\n\n  /**\n   * @return array\n   */\n  public function getResource();\n\n  /**\n   * @param array $resource\n   */\n  public function setResource($resource);\n\n  /**\n   * @return array\n   */\n  public function getMethods();\n\n  /**\n   * @param array $methods\n   *\n   * @throws ServerConfigurationException\n   */\n  public function setMethods($methods);\n\n  /**\n   * Checks if the current field is computed.\n   *\n   * @return bool\n   *   TRUE if the field is computed.\n   */\n  public function isComputed();\n\n  /**\n   * Helper method to determine if an array is numeric.\n   *\n   * @param array $input\n   *   The input array.\n   *\n   * @return boolean\n   *   TRUE if the array is numeric, false otherwise.\n   */\n  public static function isArrayNumeric(array $input);\n\n  /**\n   * Factory.\n   *\n   * @param array $field\n   *   Contains the field values.\n   * @param RequestInterface $request\n   *   The request.\n   *\n   * @return ResourceFieldInterface\n   *   The created field\n   *\n   * @throws ServerConfigurationException\n   */\n  public static function create(array $field, RequestInterface $request = NULL);\n\n  /**\n   * Gets the value for the field given a data source.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data source object. Interacts with the data storage.\n   *\n   * @return mixed\n   *   The value for the public field.\n   *\n   * @throws IncompatibleFieldDefinitionException\n   */\n  public function value(DataInterpreterInterface $interpreter);\n\n  /**\n   * Check access on property by the defined access callbacks.\n   *\n   * @param string $op\n   *   The operation that access should be checked for. Can be \"view\" or \"edit\".\n   *   Defaults to \"edit\".\n   * @param DataInterpreterInterface $interpreter\n   *   The data source representing the entity.\n   *\n   * @return bool\n   *   TRUE if the current user has access to set the property, FALSE otherwise.\n   *   The default implementation assumes that if no callback has explicitly\n   *   denied access, we grant the user permission.\n   */\n  public function access($op, DataInterpreterInterface $interpreter);\n\n  /**\n   * Gets the ID of the resource field.\n   *\n   * @return string\n   *   The ID.\n   */\n  public function id();\n\n  /**\n   * Adds the default values to the definitions array.\n   */\n  public function addDefaults();\n\n  /**\n   * Add metadata to the field.\n   *\n   * This is a general purpose metadata storage for the field to store other\n   * things that are not specifically the field value.\n   *\n   * You can pass in a namespaced $key using a : as a delimiter. Namespaces will\n   * result in nested arrays. That means that addMetadata('foo:bar:baz', 'oof')\n   * will result in metadata['foo']['bar']['baz'] = 'oof'.\n   *\n   * @param string $key\n   *   The metadata item identifier.\n   * @param mixed $value\n   *   The metadata value.\n   */\n  public function addMetadata($key, $value);\n\n  /**\n   * Add metadata to the field.\n   *\n   * This is a general purpose metadata storage for the field to store other\n   * things that are not specifically the field value.\n   *\n   * @param string $key\n   *   The metadata item identifier.\n   *\n   * @return mixed\n   *   The metadata value.\n   */\n  public function getMetadata($key);\n\n  /**\n   * Gets the value for the field given a data source.\n   *\n   * @param mixed $value\n   *   The value for the field.\n   * @param DataInterpreterInterface $interpreter\n   *   The data source object. Interacts with the data storage.\n   *\n   * @throws IncompatibleFieldDefinitionException\n   */\n  public function set($value, DataInterpreterInterface $interpreter);\n\n  /**\n   * Executes the process callbacks.\n   *\n   * @param mixed $value\n   *   The initial value.\n   *\n   * @return mixed\n   *   The processed value.\n   */\n  public function executeProcessCallbacks($value);\n\n  /**\n   * Fetches the embedded identifier(s) for the current resource field, if any.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter to get the compound ID.\n   *\n   * @return string|string[]\n   *   An identifier or an array of identifiers for cardinality > 1. NULL if\n   *   there is no identifier to be found.\n   */\n  public function compoundDocumentId(DataInterpreterInterface $interpreter);\n\n  /**\n   * Gets the value of a field and applies all process callbacks to it.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter.\n   *\n   * @return mixed\n   *   The value to render.\n   */\n  public function render(DataInterpreterInterface $interpreter);\n\n  /**\n   * Gets the cardinality of the wrapped field.\n   *\n   * @return int\n   *   The number of potentially returned fields. Reuses field cardinality\n   *   constants.\n   */\n  public function getCardinality();\n\n  /**\n   * Set the cardinality.\n   *\n   * @param int $cardinality\n   *   The new cardinality.\n   */\n  public function setCardinality($cardinality);\n\n  /**\n   * Get the request in the data provider.\n   *\n   * @return RequestInterface\n   *   The request.\n   */\n  public function getRequest();\n\n  /**\n   * Set the request.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   */\n  public function setRequest(RequestInterface $request);\n\n  /**\n   * Gets the original field definition as declared in Resource::publicFields().\n   *\n   * @return array\n   *   The field definition.\n   */\n  public function getDefinition();\n\n  /**\n   * Gets the public field info object.\n   *\n   * @return PublicFieldInfoInterface\n   *   The public field info object.\n   */\n  public function getPublicFieldInfo();\n\n  /**\n   * Gets the public field info object.\n   *\n   * @param PublicFieldInfoInterface $public_field_info\n   *   The public field info object.\n   */\n  public function setPublicFieldInfo(PublicFieldInfoInterface $public_field_info);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldKeyValue.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldKeyValue.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\nclass ResourceFieldKeyValue extends ResourceField implements ResourceFieldInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create(array $field, RequestInterface $request = NULL) {\n    $request = $request ?: restful()->getRequest();\n    $resource_field = new static($field, $request);\n    $resource_field->addDefaults();\n    return $resource_field;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function value(DataInterpreterInterface $interpreter) {\n    if ($value = parent::value($interpreter)) {\n      return $value;\n    }\n    return $interpreter->getWrapper()->get($this->getProperty());\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldReference.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldReference.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\n/**\n * Class ResourceFieldReference.\n *\n * This field type is useful when you have an arbitrary field, that is not an\n * entity reference field, that returns an ID to another resource. This resource\n * field type will allow you to have a field definition with a callback return\n * an ID and use that as a relationship.\n *\n * This is specially useful when adding a relationship to an entity based\n * resource from a DB query, or vice versa. See an example of this in action in\n * the example resource main:1.8.\n *\n * If you need to add a reference to entity things like $node->uid, use\n * \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityReference instead.\n *\n * @package Drupal\\restful\\Plugin\\resource\\Field\n */\nclass ResourceFieldReference extends ResourceField {\n\n  /**\n   * Overrides ResourceField::compoundDocumentId().\n   */\n  public function compoundDocumentId(DataInterpreterInterface $interpreter) {\n    $collection = parent::compoundDocumentId($interpreter);\n    if (!$collection instanceof ResourceFieldCollectionInterface) {\n      return NULL;\n    }\n    $id_field = $collection->getIdField();\n    if (!$id_field instanceof ResourceFieldInterface) {\n      return NULL;\n    }\n    return $id_field->render($collection->getInterpreter());\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldResource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldResource.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\PublicFieldInfo\\PublicFieldInfoInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Util\\ExplorableDecoratorInterface;\n\nclass ResourceFieldResource implements ResourceFieldResourceInterface, ExplorableDecoratorInterface {\n\n  /**\n   * Decorated resource field.\n   *\n   * @var ResourceFieldInterface\n   */\n  protected $decorated;\n\n  /**\n   * The ID on the referenced resource.\n   *\n   * @var mixed\n   */\n  protected $resourceId;\n\n  /**\n   * The machine name, without version, of the referenced resource.\n   *\n   * @var string\n   */\n  protected $resourceMachineName;\n\n  /**\n   * Resource plugin.\n   *\n   * Resource this field points to.\n   *\n   * @var ResourceInterface\n   */\n  protected $resourcePlugin;\n\n  /**\n   * Target Column.\n   *\n   * @var string\n   */\n  protected $targetColumn;\n\n  /**\n   * Constructor.\n   *\n   * @param array $field\n   *   Contains the field values.\n   *\n   * @param RequestInterface $request\n   *   The request.\n   */\n  public function __construct(array $field, RequestInterface $request) {\n    if ($this->decorated) {\n      $this->setRequest($request);\n    }\n    $this->resourceMachineName = $field['resource']['name'];\n    // Compute the target column if empty.\n    if (!empty($field['targetColumn'])) {\n      $this->targetColumn = $field['targetColumn'];\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceId(DataInterpreterInterface $interpreter) {\n    if (isset($this->resourceId)) {\n      return $this->resourceId;\n    }\n    $this->resourceId = $this->compoundDocumentId($interpreter);\n    return $this->resourceId;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceMachineName() {\n    return $this->resourceMachineName;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourcePlugin() {\n    if (isset($this->resourcePlugin)) {\n      return $this->resourcePlugin;\n    }\n    $resource_info = $this->getResource();\n    $this->resourcePlugin = restful()\n      ->getResourceManager()\n      ->getPlugin(sprintf('%s:%d.%d', $resource_info['name'], $resource_info['majorVersion'], $resource_info['minorVersion']));\n    return $this->resourcePlugin;\n  }\n\n  /**\n   * Gets the cardinality of the field.\n   *\n   * @return int\n   *   The number of potentially returned fields. Reuses field cardinality\n   *   constants.\n   */\n  public function getCardinality() {\n    if ($this->decorated instanceof ResourceFieldEntityInterface) {\n      return $this->decorated->getCardinality();\n    }\n    // Default to single cardinality.\n    return 1;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCardinality($cardinality) {\n    $this->decorated->setCardinality($cardinality);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create(array $field, RequestInterface $request = NULL) {\n    $request = $request ?: restful()->getRequest();\n    $resource_field = ResourceField::create($field, $request);\n    $output = new static($field, $request);\n    $output->decorate($resource_field);\n    return $output;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isArrayNumeric(array $input) {\n    return ResourceFieldBase::isArrayNumeric($input);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function value(DataInterpreterInterface $interpreter) {\n    return $this->decorated->value($interpreter);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function access($op, DataInterpreterInterface $interpreter) {\n    return $this->decorated->access($op, $interpreter);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addDefaults() {\n    $this->decorated->addDefaults();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($value, DataInterpreterInterface $interpreter) {\n    $this->decorated->set($value, $interpreter);\n  }\n\n\n  /**\n   * {@inheritdoc}\n   */\n  public function decorate(ResourceFieldInterface $decorated) {\n    $this->decorated = $decorated;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addMetadata($key, $value) {\n    $this->decorated->addMetadata($key, $value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMetadata($key) {\n    return $this->decorated->getMetadata($key);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function executeProcessCallbacks($value) {\n    return $this->decorated->executeProcessCallbacks($value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPublicName() {\n    return $this->decorated->getPublicName();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPublicName($public_name) {\n    $this->decorated->setPublicName($public_name);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccessCallbacks() {\n    return $this->decorated->getAccessCallbacks();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccessCallbacks($access_callbacks) {\n    $this->decorated->setAccessCallbacks($access_callbacks);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProperty() {\n    return $this->decorated->getProperty();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProperty($property) {\n    $this->decorated->setProperty($property);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCallback() {\n    return $this->decorated->getCallback();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setCallback($callback) {\n    $this->decorated->setCallback($callback);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getProcessCallbacks() {\n    return $this->decorated->getProcessCallbacks();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setProcessCallbacks($process_callbacks) {\n    $this->decorated->setProcessCallbacks($process_callbacks);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResource() {\n    return $this->decorated->getResource();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setResource($resource) {\n    $this->decorated->setResource($resource);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getMethods() {\n    return $this->decorated->getMethods();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setMethods($methods) {\n    $this->decorated->setMethods($methods);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function id() {\n    return $this->decorated->id();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isComputed() {\n    return $this->decorated->isComputed();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function compoundDocumentId(DataInterpreterInterface $interpreter) {\n    return $this->decorated->compoundDocumentId($interpreter);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function render(DataInterpreterInterface $interpreter) {\n    return $this->executeProcessCallbacks($this->value($interpreter));\n  }\n\n  /**\n   * If any method not declared, then defer it to the decorated field.\n   */\n  public function __call($name, $arguments) {\n    return call_user_func_array(array($this->decorated, $name), $arguments);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    return $this->decorated->getRequest();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->decorated->setRequest($request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDefinition() {\n    return $this->decorated->getDefinition();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPublicFieldInfo() {\n    return $this->decorated->getPublicFieldInfo();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPublicFieldInfo(PublicFieldInfoInterface $public_field_info) {\n    $this->decorated->setPublicFieldInfo($public_field_info);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function autoDiscovery() {\n    if (method_exists($this->decorated, 'autoDiscovery')) {\n      return $this->decorated->autoDiscovery();\n    }\n    return ResourceFieldBase::emptyDiscoveryInfo($this->getPublicName());\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getTargetColumn() {\n    if (empty($this->targetColumn)) {\n      // Check the definition of the decorated field.\n      $definition = $this->decorated->getDefinition();\n      if (!empty($definition['targetColumn'])) {\n        $this->targetColumn = $definition['targetColumn'];\n      }\n      elseif ($this->isInstanceOf(ResourceFieldEntityReferenceInterface::class)) {\n        $entity_info = entity_get_info($this->getResourcePlugin()->getEntityType());\n        // Assume that the relationship is through the entity key id.\n        $this->targetColumn = $entity_info['entity keys']['id'];\n      }\n      else {\n        throw new ServerConfigurationException(sprintf('Target column could not be found for field \"%s\".', $this->getPublicName()));\n      }\n    }\n    return $this->targetColumn;\n  }\n\n  /**\n   * Checks if the decorated object is an instance of something.\n   *\n   * @param string $class\n   *   Class or interface to check the instance.\n   *\n   * @return bool\n   *   TRUE if the decorated object is an instace of the $class. FALSE\n   *   otherwise.\n   */\n  public function isInstanceOf($class) {\n    if ($this instanceof $class || $this->decorated instanceof $class) {\n      return TRUE;\n    }\n    // Check if the decorated resource is also a decorator.\n    if ($this->decorated instanceof ExplorableDecoratorInterface) {\n      return $this->decorated->isInstanceOf($class);\n    }\n    return FALSE;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Field/ResourceFieldResourceInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldResourceInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource\\Field;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\ninterface ResourceFieldResourceInterface extends ResourceFieldInterface {\n\n  /**\n   * Gets the ID on the referenced resource.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter to get the compound ID.\n   *\n   * @return string|string[]\n   *   The identifier(s) used to access the resource.\n   */\n  public function getResourceId(DataInterpreterInterface $interpreter);\n\n  /**\n   * Gets the machine name, without version, of the referenced resource.\n   *\n   * @return string\n   *   The name.\n   */\n  public function getResourceMachineName();\n\n  /**\n   * Gets the destination resource plugin.\n   *\n   * @return ResourceInterface\n   *   The plugin.\n   */\n  public function getResourcePlugin();\n\n  /**\n   * Gets the table column for joins.\n   *\n   * @return string\n   *   The column to make a join for nested filters.\n   */\n  public function getTargetColumn();\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/FilesUpload__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\FilesUpload__1_0\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\restful\\Exception\\UnauthorizedException;\n\n/**\n * Class FilesUpload__1_0\n * @package Drupal\\restful_example\\Plugin\\Resource\n *\n * @Resource(\n *   name = \"files_upload:1.0\",\n *   resource = \"files_upload\",\n *   label = \"File upload\",\n *   description = \"A file upload wrapped with RESTful.\",\n *   authenticationTypes = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"file\",\n *     \"options\": {\n *       \"scheme\": \"public\"\n *     }\n *   },\n *   menuItem = \"file-upload\",\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass FilesUpload__1_0 extends ResourceEntity {\n\n  /**\n   * Constructs a FilesUpload__1_0 object.\n   *\n   * @param array $configuration\n   *   A configuration array containing information about the plugin instance.\n   * @param string $plugin_id\n   *   The plugin_id for the plugin instance.\n   * @param mixed $plugin_definition\n   *   The plugin implementation definition.\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n    // Set dynamic options that cannot be set in the annotation.\n    $plugin_definition = $this->getPluginDefinition();\n    $plugin_definition['authenticationOptional'] = (bool) variable_get('restful_file_upload_allow_anonymous_user', FALSE);\n\n    // Store the plugin definition.\n    $this->pluginDefinition = $plugin_definition;\n  }\n\n  /**\n   * {@inheritdoc}\n   *\n   * If \"File entity\" module exists, determine access by its provided\n   * permissions otherwise, check if variable is set to allow anonymous users to\n   * upload. Defaults to authenticated user.\n   */\n  public function access() {\n    // The getAccount method may return an UnauthorizedException when an\n    // authenticated user cannot be found. Since this is called from the access\n    // callback, not from the page callback we need to catch the exception.\n    try {\n      $account = $this->getAccount();\n    }\n    catch (UnauthorizedException $e) {\n      // If a user is not found then load the anonymous user to check\n      // permissions.\n      $account = drupal_anonymous_user();\n    }\n    if (module_exists('file_entity')) {\n      return user_access('bypass file access', $account) || user_access('create files', $account);\n    }\n\n    return (variable_get('restful_file_upload_allow_anonymous_user', FALSE) || $account->uid) && parent::access();\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/LoginCookie__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\LoginCookie__1_0.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceField;\n\n/**\n * Class LoginCookie__1_0\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"login_cookie:1.0\",\n *   resource = \"login_cookie\",\n *   label = \"Login\",\n *   description = \"Login a user and return a JSON along with the authentication cookie.\",\n *   authenticationTypes = {\n *     \"basic_auth\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"user\",\n *     \"bundles\": {\n *       \"user\"\n *     },\n *   },\n *   menuItem = \"login\",\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass LoginCookie__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function publicFields() {\n    $public_fields = parent::publicFields();\n    $public_fields['id']['methods'] = array();\n\n    // Just return the hidden ID.\n    return array('id' => $public_fields['id']);\n  }\n\n  /**\n   * Overrides \\RestfulBase::controllersInfo().\n   */\n  public function controllersInfo() {\n    return array(\n      '' => array(\n        RequestInterface::METHOD_GET => 'loginAndRespondWithCookie',\n      ),\n    );\n  }\n\n  /**\n   * Login a user and return a JSON along with the authentication cookie.\n   *\n   * @return array\n   *   Array with the public fields populated.\n   */\n  public function loginAndRespondWithCookie() {\n    // Login the user.\n    $account = $this->getAccount();\n    $this->loginUser($account);\n\n    $user_resource = restful()\n      ->getResourceManager()\n      ->getPlugin('users:1.0');\n\n    // User resource may be disabled.\n    $output = $user_resource ? $user_resource->view($account->uid) : array();\n    if ($resource_field_collection = reset($output)) {\n      /* @var $resource_field_collection \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface */\n      $resource_field_collection->set('X-CSRF-Token', ResourceField::create(array(\n        'public_name' => 'X-CSRF-Token',\n        'callback' => '\\Drupal\\restful\\Plugin\\resource\\LoginCookie__1_0::getCSRFTokenValue',\n      )));\n    }\n    return $output;\n  }\n\n  /**\n   * Log the user in.\n   *\n   * @param object $account\n   *   The user object that was retrieved by the AuthenticationManager.\n   */\n  public function loginUser($account) {\n    global $user;\n\n    $this->authenticationManager->switchUserBack();\n    // Explicitly allow a session to be saved, as it was disabled in\n    // UserSessionState::switchUser. However this resource is a special one, in\n    // the sense that we want to keep the user authenticated after login.\n    drupal_save_session(TRUE);\n\n    // Override the global user.\n    $user = user_load($account->uid);\n\n    $login_array = array('name' => $account->name);\n    user_login_finalize($login_array);\n  }\n\n  /**\n   * Get the CSRF token string.\n   *\n   * @return string\n   *   The token.\n   */\n  public static function getCSRFTokenValue() {\n    $token = array_values(restful_csrf_session_token());\n    return reset($token);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function switchUserBack() {\n    // We don't want to switch back in this case!\n    drupal_save_session(TRUE);\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Resource.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Resource.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Authentication\\AuthenticationManager;\nuse Drupal\\restful\\Authentication\\AuthenticationManagerInterface;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\ForbiddenException;\nuse Drupal\\restful\\Exception\\GoneException;\nuse Drupal\\restful\\Exception\\NotImplementedException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\UnauthorizedException;\nuse Drupal\\restful\\Http\\HttpHeader;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\ConfigurablePluginTrait;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\nuse Drupal\\restful\\Resource\\ResourceManager;\n\nabstract class Resource extends PluginBase implements ResourceInterface {\n\n  use ConfigurablePluginTrait;\n\n  /**\n   * The requested path.\n   *\n   * @var string\n   */\n  protected $path;\n\n  /**\n   * The current request.\n   *\n   * @var RequestInterface\n   */\n  protected $request;\n\n  /**\n   * The data provider.\n   *\n   * @var DataProviderInterface\n   */\n  protected $dataProvider;\n\n  /**\n   * The field definition object.\n   *\n   * @var ResourceFieldCollectionInterface\n   */\n  protected $fieldDefinitions;\n\n  /**\n   * The authentication manager.\n   *\n   * @var AuthenticationManagerInterface\n   */\n  protected $authenticationManager;\n\n  /**\n   * Indicates if the resource is enabled.\n   *\n   * @var bool\n   */\n  protected $enabled = TRUE;\n\n  /**\n   * Constructs a Drupal\\Component\\Plugin\\PluginBase object.\n   *\n   * @param array $configuration\n   *   A configuration array containing information about the plugin instance.\n   * @param string $plugin_id\n   *   The plugin_id for the plugin instance.\n   * @param mixed $plugin_definition\n   *   The plugin implementation definition.\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n    $this->fieldDefinitions = ResourceFieldCollection::factory($this->processPublicFields($this->publicFields()), $this->getRequest());\n\n    $this->initAuthenticationManager();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function dataProviderFactory() {\n    $plugin_definition = $this->getPluginDefinition();\n    $field_definitions = $this->getFieldDefinitions();\n    $class_name = $this->dataProviderClassName();\n    if (!class_exists($class_name)) {\n      throw new ServerConfigurationException(sprintf('The DataProvider could not be found for this resource: %s.', $this->getResourceMachineName()));\n    }\n    return new $class_name($this->getRequest(), $field_definitions, $this->getAccount(), $this->getPluginId(), $this->getPath(), $plugin_definition['dataProvider']);\n  }\n\n  /**\n   * Data provider class.\n   *\n   * @return string\n   *   The name of the class of the provider factory.\n   */\n  protected function dataProviderClassName() {\n    // Fallback to the null data provider, this means that we can only get data\n    // from basic callbacks.\n    return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderNull';\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getAccount($cache = TRUE) {\n    return $this->authenticationManager->getAccount($this->getRequest(), $cache);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function switchUserBack() {\n    return $this->authenticationManager->switchUserBack();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account) {\n    $this->authenticationManager->setAccount($account);\n    $this->getDataProvider()->setAccount($account);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRequest() {\n    if (isset($this->request)) {\n      return $this->request;\n    }\n    $instance_configuration = $this->getConfiguration();\n    if (!$this->request = $instance_configuration['request']) {\n      throw new ServerConfigurationException('Request object is not available for the Resource plugin.');\n    }\n    return $this->request;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->request = $request;\n    // Make sure that the request is updated in the data provider.\n    $this->getDataProvider()->setRequest($request);\n    foreach ($this->fieldDefinitions as $resource_field) {\n      /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface $resource_field */\n      $resource_field->setRequest($request);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPath() {\n    return $this->path;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPath($path) {\n    $this->path = $path;\n    $this->getDataProvider()->setResourcePath($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getFieldDefinitions() {\n    return $this->fieldDefinitions;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setFieldDefinitions(ResourceFieldCollectionInterface $field_definitions) {\n    $this->fieldDefinitions = $field_definitions;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getDataProvider() {\n    if (isset($this->dataProvider)) {\n      return $this->dataProvider;\n    }\n    $this->dataProvider = $this->dataProviderFactory();\n    return $this->dataProvider;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setDataProvider(DataProviderInterface $data_provider = NULL) {\n    $this->dataProvider = $data_provider;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceName() {\n    $definition = $this->getPluginDefinition();\n    return $definition['name'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceMachineName() {\n    $definition = $this->getPluginDefinition();\n    return $definition['resource'];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function defaultConfiguration() {\n    return array(\n      'request' => restful()->getRequest(),\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function process() {\n    $path = $this->getPath();\n\n    return ResourceManager::executeCallback($this->getControllerFromPath($path), array($path));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doGet($path = '', array $query = array()) {\n    $this->setPath($path);\n    $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), $query, RequestInterface::METHOD_GET));\n    return $this->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doPost(array $parsed_body) {\n    return $this->doWrite(RequestInterface::METHOD_POST, '', $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doPatch($path, array $parsed_body) {\n    if (!$path) {\n      throw new BadRequestException('PATCH requires a path. None given.');\n    }\n    return $this->doWrite(RequestInterface::METHOD_PATCH, $path, $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doPut($path, array $parsed_body) {\n    if (!$path) {\n      throw new BadRequestException('PUT requires a path. None given.');\n    }\n    return $this->doWrite(RequestInterface::METHOD_PUT, $path, $parsed_body);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  private function doWrite($method, $path, array $parsed_body) {\n    $this->setPath($path);\n    $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), array(), $method, NULL, FALSE, NULL, array(), array(), array(), $parsed_body));\n    return $this->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function doDelete($path) {\n    if (!$path) {\n      throw new BadRequestException('DELETE requires a path. None given.');\n    }\n    $this->setPath($path);\n    $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), array(), RequestInterface::METHOD_DELETE));\n    return $this->process();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function controllersInfo() {\n    return array(\n      '' => array(\n        // GET returns a list of entities.\n        RequestInterface::METHOD_GET => 'index',\n        RequestInterface::METHOD_HEAD => 'index',\n        // POST.\n        RequestInterface::METHOD_POST => 'create',\n        RequestInterface::METHOD_OPTIONS => 'discover',\n      ),\n      // We don't know what the ID looks like, assume that everything is the ID.\n      '^.*$' => array(\n        RequestInterface::METHOD_GET => 'view',\n        RequestInterface::METHOD_HEAD => 'view',\n        RequestInterface::METHOD_PUT => 'replace',\n        RequestInterface::METHOD_PATCH => 'update',\n        RequestInterface::METHOD_DELETE => 'remove',\n        RequestInterface::METHOD_OPTIONS => 'discover',\n      ),\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getControllers() {\n    $controllers = array();\n    foreach ($this->controllersInfo() as $path => $method_info) {\n      $controllers[$path] = array();\n      foreach ($method_info as $http_method => $controller_info) {\n        $controllers[$path][$http_method] = $controller_info;\n        if (!is_array($controller_info)) {\n          $controllers[$path][$http_method] = array('callback' => $controller_info);\n        }\n      }\n    }\n\n    return $controllers;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function index($path) {\n    return $this->getDataProvider()->index();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function view($path) {\n    // TODO: Compare this with 1.x logic.\n    $ids = explode(static::IDS_SEPARATOR, $path);\n\n    // REST requires a canonical URL for every resource.\n    $canonical_path = $this->getDataProvider()->canonicalPath($path);\n    restful()\n      ->getResponse()\n      ->getHeaders()\n      ->add(HttpHeader::create('Link', $this->versionedUrl($canonical_path, array(), FALSE) . '; rel=\"canonical\"'));\n\n    // If there is only one ID then use 'view'. Else, use 'viewMultiple'. The\n    // difference between the two is that 'view' allows access denied\n    // exceptions.\n    if (count($ids) == 1) {\n      return array($this->getDataProvider()->view($ids[0]));\n    }\n    else {\n      return $this->getDataProvider()->viewMultiple($ids);\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function create($path) {\n    // TODO: Compare this with 1.x logic.\n    $object = $this->getRequest()->getParsedBody();\n    return $this->getDataProvider()->create($object);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function update($path) {\n    // TODO: Compare this with 1.x logic.\n    $object = $this->getRequest()->getParsedBody();\n    return $this->getDataProvider()->update($path, $object, FALSE);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function replace($path) {\n    // TODO: Compare this with 1.x logic.\n    $object = $this->getRequest()->getParsedBody();\n    return $this->getDataProvider()->update($path, $object, TRUE);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function remove($path) {\n    // TODO: Compare this with 1.x logic.\n    $this->getDataProvider()->remove($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function discover($path = NULL) {\n    $this->preflight($path);\n    return $this->getDataProvider()->discover($path);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getControllerFromPath($path = NULL, ResourceInterface $resource = NULL) {\n    if (empty($resource)) {\n      $resource = $this;\n    }\n    $path = $path ?: $resource->getPath();\n    $method = $resource->getRequest()->getMethod();\n    $selected_controller = NULL;\n    foreach ($resource->getControllers() as $pattern => $controllers) {\n      // Find the controllers for the provided path.\n      if ($pattern != $path && !($pattern && preg_match('/' . $pattern . '/', $path))) {\n        continue;\n      }\n\n      if ($controllers === FALSE) {\n        // Method isn't valid anymore, due to a deprecated API endpoint.\n        $params = array('@path' => $path);\n        throw new GoneException(format_string('The path @path endpoint is not valid.', $params));\n      }\n\n      if (!isset($controllers[$method])) {\n        $params = array('@method' => strtoupper($method));\n        throw new BadRequestException(format_string('The http method @method is not allowed for this path.', $params));\n      }\n\n      // We found the controller, so we can break.\n      $selected_controller = $controllers[$method];\n      if (is_array($selected_controller)) {\n        // If there is a custom access method for this endpoint check it.\n        if (!empty($selected_controller['access callback']) && !ResourceManager::executeCallback(array($resource, $selected_controller['access callback']), array($path))) {\n          throw new ForbiddenException(sprintf('You do not have access to this endpoint: %s - %s', $method, $path));\n        }\n        $selected_controller = $selected_controller['callback'];\n      }\n\n      // Create the callable from the method string.\n      if (!ResourceManager::isValidCallback($selected_controller)) {\n        // This means that the provided value means to be a public method on the\n        // current class.\n        $selected_controller = array($resource, $selected_controller);\n      }\n      break;\n    }\n\n    if (empty($selected_controller)) {\n      throw new NotImplementedException(sprintf('There is no handler for \"%s\" on the path: %s', $resource->getRequest()->getMethod(), $path));\n    }\n\n    return $selected_controller;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getVersion() {\n    $plugin_definition = $this->getPluginDefinition();\n    $version = array(\n      'major' => $plugin_definition['majorVersion'],\n      'minor' => $plugin_definition['minorVersion'],\n    );\n    return $version;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function versionedUrl($path = '', $options = array(), $version_string = TRUE) {\n    // Make the URL absolute by default.\n    $options += array('absolute' => TRUE);\n    $plugin_definition = $this->getPluginDefinition();\n    if (!empty($plugin_definition['menuItem'])) {\n      $url = variable_get('restful_hook_menu_base_path', 'api') . '/';\n      $url .= $plugin_definition['menuItem'] . '/' . $path;\n      return url(rtrim($url, '/'), $options);\n    }\n\n    $base_path = variable_get('restful_hook_menu_base_path', 'api');\n    $url = $base_path;\n    if ($version_string) {\n      $url .= '/v' . $plugin_definition['majorVersion'] . '.' . $plugin_definition['minorVersion'];\n    }\n    $url .= '/' . $plugin_definition['resource'] . '/' . $path;\n    return url(rtrim($url, '/'), $options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getUrl(array $options = array(), $keep_query = TRUE, RequestInterface $request = NULL) {\n    // By default set URL to be absolute.\n    $options += array(\n      'absolute' => TRUE,\n      'query' => array(),\n    );\n\n    if ($keep_query) {\n      $request  = $request ?: $this->getRequest();\n      $input = $request->getParsedInput();\n      unset($input['page']);\n      unset($input['range']);\n      $input['page'] = $request->getPagerInput();\n      // Remove special params.\n      unset($input['q']);\n\n      // Add the request as query strings.\n      $options['query'] += $input;\n    }\n\n    return $this->versionedUrl($this->getPath(), $options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function access() {\n    return $this->accessByAllowOrigin();\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function enable() {\n    $this->enabled = TRUE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function disable() {\n    $this->enabled = FALSE;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function isEnabled() {\n    return $this->enabled;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setPluginDefinition(array $plugin_definition) {\n    $this->pluginDefinition = $plugin_definition;\n    if (!empty($plugin_definition['dataProvider'])) {\n      $this->getDataProvider()->addOptions($plugin_definition['dataProvider']);\n    }\n  }\n\n  /**\n   * Checks access based on the referer header and the allowOrigin setting.\n   *\n   * @return bool\n   *   TRUE if the access is granted. FALSE otherwise.\n   */\n  protected function accessByAllowOrigin() {\n    // Check the referrer header and return false if it does not match the\n    // Access-Control-Allow-Origin\n    $referer = $this->getRequest()->getHeaders()->get('Referer')->getValueString();\n\n    // If there is no allow_origin assume that it is allowed. Also, if there is\n    // no referer then grant access since the request probably was not\n    // originated from a browser.\n    $plugin_definition = $this->getPluginDefinition();\n    $origin = isset($plugin_definition['allowOrigin']) ? $plugin_definition['allowOrigin'] : NULL;\n    if (empty($origin) || $origin == '*' || !$referer) {\n      return TRUE;\n    }\n    return strpos($referer, $origin) === 0;\n  }\n\n  /**\n   * Public fields.\n   *\n   * @return array\n   *   The field definition array.\n   */\n  abstract protected function publicFields();\n\n  /**\n   * Get the public fields with the default values applied to them.\n   *\n   * @param array $field_definitions\n   *   The field definitions to process.\n   *\n   * @return array\n   *   The field definition array.\n   */\n  protected function processPublicFields(array $field_definitions) {\n    // By default do not do any special processing.\n    return $field_definitions;\n  }\n\n  /**\n   * Initializes the authentication manager and adds the appropriate providers.\n   *\n   * This will return an AuthenticationManagerInterface if the current resource\n   * needs to be authenticated. To skip authentication completely do not set\n   * authenticationTypes and set authenticationOptional to TRUE.\n   */\n  protected function initAuthenticationManager() {\n    $this->authenticationManager = new AuthenticationManager();\n\n    $plugin_definition = $this->getPluginDefinition();\n    $authentication_types = $plugin_definition['authenticationTypes'];\n    $authentication_optional = $plugin_definition['authenticationOptional'];\n    $this->authenticationManager->setIsOptional($authentication_optional);\n    if (empty($authentication_types)) {\n      if (empty($authentication_optional)) {\n        // Fail early, fail good.\n        throw new UnauthorizedException('There are no authentication providers and authentication is not optional.');\n      }\n      return;\n    }\n    if ($authentication_types === TRUE) {\n      // Add all the available authentication providers to the manager.\n      $this->authenticationManager->addAllAuthenticationProviders();\n      return;\n    }\n    foreach ($authentication_types as $authentication_type) {\n      // Read the authentication providers and add them to the manager.\n      $this->authenticationManager->addAuthenticationProvider($authentication_type);\n    }\n  }\n\n  /**\n   * Adds the Allowed-Origin headers.\n   *\n   * @param string $path\n   *   The requested path.\n   */\n  protected function preflight($path) {\n    $plugin_definition = $this->getPluginDefinition();\n    $header_bag = restful()\n      ->getResponse()\n      ->getHeaders();\n\n    // Populate the Accept header.\n    $accepted_formats = array();\n    $formatter_manager = restful()->getFormatterManager();\n    if (empty($plugin_definition['formatter'])) {\n      foreach ($formatter_manager->getPlugins() as $formatter) {\n        /** @var $formatter \\Drupal\\restful\\Plugin\\formatter\\FormatterInterface */\n        $header_bag->append(HttpHeader::create('Accept', $formatter->getContentTypeHeader()));\n      }\n    }\n    else {\n      try {\n        $accepted_format = $formatter_manager\n          ->getPlugin($plugin_definition['formatter'])\n          ->getContentTypeHeader();\n        $header_bag->add(HttpHeader::create('Accept', $accepted_format));\n      }\n      catch(PluginNotFoundException $e) {\n        throw new NotImplementedException($e->getMessage());\n      }\n    }\n\n    $allowed_origin = empty($plugin_definition['allowOrigin']) ? variable_get('restful_allowed_origin', NULL) : $plugin_definition['allowOrigin'];\n    // Always add the allow origin if configured.\n    if ($allowed_origin) {\n      $header_bag->add(HttpHeader::create('Access-Control-Allow-Origin', check_plain($allowed_origin)));\n      // @see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials\n      $accepts_credentials = $allowed_origin == '*' ? 'false' : 'true';\n      $header_bag->add(HttpHeader::create('Access-Control-Allow-Credentials', $accepts_credentials));\n    }\n    // Make sure the Access-Control-Allow-Methods is populated.\n    $allowed_methods = array();\n    foreach ($this->getControllers() as $pattern => $controllers) {\n      // Find the controllers for the provided path.\n      if ($pattern == $path || ($pattern && preg_match('/' . $pattern . '/', $path))) {\n        foreach ($controllers as $method => $controller) {\n          if (is_array($controller)) {\n            // If there is a custom access method for this endpoint check it.\n            if (!empty($selected_controller['access callback']) && !ResourceManager::executeCallback(array($this, $selected_controller['access callback']), array($path))) {\n              // There is no access for this method.\n              continue;\n            }\n          }\n          $allowed_methods[] = $method;\n        }\n        $header_bag->add(HttpHeader::create(\n          'Access-Control-Allow-Methods',\n          implode(',', $allowed_methods)\n        ));\n        break;\n      }\n    }\n\n  }\n}\n"
  },
  {
    "path": "src/Plugin/resource/ResourceDbQuery.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\ResourceDbQuery.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nabstract class ResourceDbQuery extends Resource implements ResourceInterface {\n\n  /**\n   * Get the public fields with the default values applied to them.\n   *\n   * @param array $field_definitions\n   *   The field definitions to process.\n   *\n   * @return array\n   *   The field definition array.\n   */\n  protected function processPublicFields(array $field_definitions) {\n    // The fields that only contain a property need to be set to be\n    // ResourceFieldEntity. Otherwise they will be considered regular\n    // ResourceField.\n    return array_map(function ($field_definition) {\n      return $field_definition + array('class' => '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldDbColumn');\n    }, $field_definitions);\n  }\n\n  /**\n   * Data provider class.\n   *\n   * @return string\n   *   The name of the class of the provider factory.\n   */\n  protected function dataProviderClassName() {\n    return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderDbQuery';\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/ResourceEntity.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\ResourceEntity.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\restful\\Exception\\InternalServerErrorException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntityInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntity;\n\nabstract class ResourceEntity extends Resource {\n\n  /**\n   * The entity type.\n   *\n   * @var string\n   */\n  protected $entityType;\n\n  /**\n   * The entity bundles.\n   *\n   * @var array\n   */\n  protected $bundles = array();\n\n  /**\n   * {@inheritdoc}\n   */\n  public function __construct(array $configuration, $plugin_id, $plugin_definition) {\n    if (empty($plugin_definition['dataProvider']['entityType'])) {\n      throw new InternalServerErrorException('The entity type was not provided.');\n    }\n    $this->entityType = $plugin_definition['dataProvider']['entityType'];\n    if (isset($plugin_definition['dataProvider']['bundles'])) {\n      $this->bundles = $plugin_definition['dataProvider']['bundles'];\n    }\n    parent::__construct($configuration, $plugin_id, $plugin_definition);\n  }\n\n  /**\n   * Data provider factory.\n   *\n   * @return DataProviderEntityInterface\n   *   The data provider for this resource.\n   *\n   * @throws ServerConfigurationException\n   */\n  public function dataProviderFactory() {\n    $plugin_definition = $this->getPluginDefinition();\n    $field_definitions = $this->getFieldDefinitions();\n    if (!empty($plugin_definition['dataProvider']['viewMode'])) {\n      $field_definitions_array = $this->viewModeFields($plugin_definition['dataProvider']['viewMode']);\n      $field_definitions = ResourceFieldCollection::factory($field_definitions_array, $this->getRequest());\n    }\n    $class_name = $this->dataProviderClassName();\n    if (!class_exists($class_name)) {\n      throw new ServerConfigurationException(sprintf('The DataProvider could not be found for this resource: %s.', $this->getResourceMachineName()));\n    }\n    return new $class_name($this->getRequest(), $field_definitions, $this->getAccount(), $this->getPluginId(), $this->getPath(), $plugin_definition['dataProvider']);\n  }\n\n  /**\n   * Data provider class.\n   *\n   * @return string\n   *   The name of the class of the provider factory.\n   */\n  protected function dataProviderClassName() {\n    // This helper function allows to map a resource to a different data\n    // provider class.\n    if ($this->getEntityType() == 'node') {\n      return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderNode';\n    }\n    elseif ($this->getEntityType() == 'taxonomy_term') {\n      return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderTaxonomyTerm';\n    }\n    elseif ($this->getEntityType() == 'file') {\n      return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderFile';\n    }\n    return '\\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderEntity';\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $public_fields = array();\n    $public_fields['id'] = array(\n      'wrapper_method' => 'getIdentifier',\n      'wrapper_method_on_entity' => TRUE,\n      'methods' => array(RequestInterface::METHOD_GET, RequestInterface::METHOD_OPTIONS),\n      'discovery' => array(\n        // Information about the field for human consumption.\n        'info' => array(\n          'label' => t('ID'),\n          'description' => t('Base ID for the entity.'),\n        ),\n        // Describe the data.\n        'data' => array(\n          'cardinality' => 1,\n          'read_only' => TRUE,\n          'type' => 'integer',\n          'required' => TRUE,\n        ),\n      ),\n    );\n    $public_fields['label'] = array(\n      'wrapper_method' => 'label',\n      'wrapper_method_on_entity' => TRUE,\n      'discovery' => array(\n        // Information about the field for human consumption.\n        'info' => array(\n          'label' => t('Label'),\n          'description' => t('The label of the resource.'),\n        ),\n        // Describe the data.\n        'data' => array(\n          'type' => 'string',\n        ),\n        // Information about the form element.\n        'form_element' => array(\n          'type' => 'textfield',\n          'size' => 255,\n        ),\n      ),\n    );\n    $public_fields['self'] = array(\n      'callback' => array($this, 'getEntitySelf'),\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * Gets the entity type.\n   *\n   * @return string\n   *   The entity type.\n   */\n  public function getEntityType() {\n    return $this->entityType;\n  }\n\n  /**\n   * Gets the entity bundle.\n   *\n   * @return array\n   *   The bundles.\n   */\n  public function getBundles() {\n    return $this->bundles;\n  }\n\n  /**\n   * Get the \"self\" url.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The wrapped entity.\n   *\n   * @return string\n   *   The self URL.\n   */\n  public function getEntitySelf(DataInterpreterInterface $interpreter) {\n    return $this->versionedUrl($interpreter->getWrapper()->getIdentifier());\n  }\n\n  /**\n   * Get the public fields with the default values applied to them.\n   *\n   * @param array $field_definitions\n   *   The field definitions to process.\n   *\n   * @throws \\Drupal\\restful\\Exception\\ServerConfigurationException\n   *   For resources without ID field.\n   *\n   * @return array\n   *   The field definition array.\n   */\n  protected function processPublicFields(array $field_definitions) {\n    // The fields that only contain a property need to be set to be\n    // ResourceFieldEntity. Otherwise they will be considered regular\n    // ResourceField.\n    return array_map(function ($field_definition) {\n      $field_entity_class = '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntity';\n      $class_name = ResourceFieldEntity::fieldClassName($field_definition);\n      if (!$class_name || is_subclass_of($class_name, $field_entity_class)) {\n        $class_name = $field_entity_class;\n      }\n      return $field_definition + array('class' => $class_name, 'entityType' => $this->getEntityType());\n    }, $field_definitions);\n  }\n\n  /**\n   * Get the public fields with default values based on view mode information.\n   *\n   * @param array $view_mode_info\n   *   View mode configuration array.\n   *\n   * @return array\n   *   The public fields.\n   *\n   * @throws ServerConfigurationException\n   */\n  protected function viewModeFields(array $view_mode_info) {\n    $field_definitions = array();\n    $entity_type = $this->getEntityType();\n    $bundles = $this->getBundles();\n    $view_mode = $view_mode_info['name'];\n    if (count($bundles) != 1) {\n      throw new ServerConfigurationException('View modes can only be used in resources with a single bundle.');\n    }\n    $bundle = reset($bundles);\n    foreach ($view_mode_info['fieldMap'] as $field_name => $public_field_name) {\n      $field_instance = field_info_instance($entity_type, $field_name, $bundle);\n      $formatter_info = $field_instance['display'][$view_mode];\n      unset($formatter_info['module']);\n      unset($formatter_info['weight']);\n      unset($formatter_info['label']);\n      $field_definitions[$public_field_name] = array(\n        'property' => $field_name,\n        'formatter' => $formatter_info,\n        'entityType' => $this->getEntityType(),\n      );\n    }\n    return $field_definitions;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/ResourceInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\ResourceInterface.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\nuse Drupal\\Component\\Plugin\\ConfigurablePluginInterface;\nuse Drupal\\Component\\Plugin\\PluginInspectionInterface;\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\ForbiddenException;\nuse Drupal\\restful\\Exception\\GoneException;\nuse Drupal\\restful\\Exception\\NotImplementedException;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\n\n/**\n * Interface ResourceInterface.\n *\n * @package Drupal\\restful\\Plugin\\resource\n */\ninterface ResourceInterface extends PluginInspectionInterface, ConfigurablePluginInterface {\n\n  /**\n   * The string that separates multiple ids.\n   */\n  const IDS_SEPARATOR = ',';\n\n  /**\n   * Data provider factory.\n   *\n   * @return DataProviderInterface\n   *   The data provider for this resource.\n   *\n   * @throws NotImplementedException\n   * @throws ServerConfigurationException\n   */\n  public function dataProviderFactory();\n\n  /**\n   * Get the user from for request.\n   *\n   * @param bool $cache\n   *   Boolean indicating if the resolved user should be cached for next calls.\n   *\n   * @return object\n   *   The fully loaded user object.\n   *\n   * @see AuthenticatedResource\n   */\n  public function getAccount($cache = TRUE);\n\n  /**\n   * Switches the user back from the original user for the session.\n   */\n  public function switchUserBack();\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setAccount($account);\n\n  /**\n   * Get the request object.\n   *\n   * @return RequestInterface\n   *   The request object.\n   *\n   * @throws \\Drupal\\restful\\Exception\\ServerConfigurationException\n   */\n  public function getRequest();\n\n  /**\n   * Sets the request object.\n   *\n   * @param RequestInterface $request\n   *   The request object.\n   */\n  public function setRequest(RequestInterface $request);\n\n  /**\n   * Gets the path of the resource.\n   *\n   * The resource path is different from the request path in that it does not\n   * contain the RESTful API prefix, the optional version string nor the\n   * resource name. All that information is already present in the resource\n   * object. The resource path only contains information used to query the data\n   * provider.\n   *\n   * @return string\n   *   The resource path.\n   */\n  public function getPath();\n\n  /**\n   * Sets the path of the resource.\n   *\n   * @param string $path\n   *   The path without the RESTful prefix or the version string.\n   */\n  public function setPath($path);\n\n  /**\n   * Gets the field definitions.\n   *\n   * @return ResourceFieldCollectionInterface\n   *   The field definitions\n   */\n  public function getFieldDefinitions();\n\n  /**\n   * Sets the field definitions.\n   *\n   * @param ResourceFieldCollectionInterface $field_definitions\n   *   The field definitions to set.\n   */\n  public function setFieldDefinitions(ResourceFieldCollectionInterface $field_definitions);\n\n  /**\n   * Gets the data provider.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderInterface\n   *   The data provider to access the backend storage.\n   */\n  public function getDataProvider();\n\n  /**\n   * Gets the resource name.\n   *\n   * @returns string\n   *   The name of the current resource.\n   */\n  public function getResourceName();\n\n  /**\n   * Gets the resource machine name.\n   *\n   * @return string\n   *   The machine name.\n   */\n  public function getResourceMachineName();\n\n  /**\n   * Controller function that passes the data along and executes right action.\n   *\n   * @return array\n   *   An structured array with the response data.\n   *\n   * @throws \\Drupal\\restful\\Exception\\NotImplementedException\n   *   If no controller can be found.\n   * @throws \\Drupal\\restful\\Exception\\ForbiddenException\n   *   If access is denied for the operation.\n   */\n  public function process();\n\n  /**\n   * Gets the controllers.\n   *\n   * @return array\n   *   An structured configuration array. Contains the regular expression for\n   *   the path as the key and an array of key values as its value. That array\n   *   of key values contains the HTTP method as the key and the name of the\n   *   public method to execute as the value. If an access callback is needed\n   *   one can be provided by turning the value into an array with the keys:\n   *   'callback' and 'access callback'.\n   *\n   * @see getControllers()\n   */\n  public function controllersInfo();\n\n  /**\n   * Gets the controllers for this resource.\n   *\n   * @return array\n   *   An structured configuration array. Contains the regular expression for\n   *   the path as the key and an array of key values as its value. That array\n   *   of key values contains the HTTP method as the key and an array with the\n   *   callback information as the value.\n   *\n   *   The callback can be anything that ResourceManager::executeCallback\n   *   accepts or a string indicating a public method in the resource plugin\n   *   class.\n   *\n   * @code{\n   *   array(\n   *     '^.*$' => array(RequestInterface::METHOD_GET => array(\n   *       'callback' => 'view',\n   *       'access callback' => array($this, 'viewAccess'),\n   *     )),\n   *   );\n   * }\n   *\n   * @todo: Populate the entity controllers so that they have the entity access checks in here.\n   */\n  public function getControllers();\n  /**\n   * Basic implementation for listing.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @return array\n   *   An array of structured data for the things being viewed.\n   */\n  public function index($path);\n\n  /**\n   * Basic implementation for view.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @return array\n   *   An array of structured data for the things being viewed.\n   */\n  public function view($path);\n\n  /**\n   * Basic implementation for create.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @return array\n   *   An array of structured data for the thing that was created.\n   */\n  public function create($path);\n\n  /**\n   * Basic implementation for update.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @return array\n   *   An array of structured data for the thing that was updated.\n   */\n  public function update($path);\n\n  /**\n   * Basic implementation for update.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @return array\n   *   An array of structured data for the thing that was replaced.\n   */\n  public function replace($path);\n  /**\n   * Basic implementation for update.\n   *\n   * @param string $path\n   *   The resource path.\n   */\n  public function remove($path);\n\n  /**\n   * Return array keyed with the major and minor version of the resource.\n   *\n   * @return array\n   *   Keyed array with the major and minor version as provided in the plugin\n   *   definition.\n   */\n  public function getVersion();\n\n  /**\n   * Gets a resource URL based on the current version.\n   *\n   * @param string $path\n   *   The path for the resource\n   * @param array $options\n   *   Array of options as in url().\n   * @param bool $version_string\n   *   TRUE to add the version string to the URL. FALSE otherwise.\n   *\n   * @return string\n   *   The fully qualified URL.\n   *\n   * @see url()\n   */\n  public function versionedUrl($path = '', $options = array(), $version_string = TRUE);\n\n  /**\n   * Determine if user can access the handler.\n   *\n   * @return bool\n   *   TRUE if the current request has access to the requested resource. FALSE\n   *   otherwise.\n   */\n  public function access();\n\n  /**\n   * Return the controller for a given path.\n   *\n   * @param string $path\n   *   (optional) The path to use. If none is provided the path from the\n   *   resource will be used.\n   * @param ResourceInterface $resource\n   *   (optional) Use the passed in resource instead of $this. This is mainly\n   *   used by decorator resources.\n   *\n   * @return callable\n   *   A callable as expected by ResourceManager::executeCallback.\n   *\n   * @throws BadRequestException\n   * @throws ForbiddenException\n   * @throws GoneException\n   * @throws NotImplementedException\n   * @throws ServerConfigurationException\n   *\n   * @see ResourceManager::executeCallback()\n   */\n  public function getControllerFromPath($path = NULL, ResourceInterface $resource = NULL);\n\n  /**\n   * Enable the resource.\n   */\n  public function enable();\n\n  /**\n   * Disable the resource.\n   */\n  public function disable();\n\n  /**\n   * Checks if the resource is enabled.\n   *\n   * @return bool\n   *   TRUE if the resource plugin is enabled.\n   */\n  public function isEnabled();\n\n  /**\n   * Sets the data provider.\n   *\n   * @param DataProviderInterface $data_provider\n   *   The data provider to set.\n   */\n  public function setDataProvider(DataProviderInterface $data_provider = NULL);\n\n  /**\n   * Sets the plugin definition to the provided array.\n   *\n   * @param array $plugin_definition\n   *   Definition array to set manually.\n   */\n  public function setPluginDefinition(array $plugin_definition);\n\n  /**\n   * Helper method; Get the URL of the resource and query strings.\n   *\n   * By default the URL is absolute.\n   *\n   * @param array $options\n   *   Array with options passed to url().\n   * @param bool $keep_query\n   *   If TRUE the $request will be appended to the $options['query']. This is\n   *   the typical behavior for $_GET method, however it is not for $_POST.\n   *   Defaults to TRUE.\n   * @param RequestInterface $request\n   *   The request object.\n   *\n   * @return string\n   *   The URL address.\n   */\n  public function getUrl(array $options = array(), $keep_query = TRUE, RequestInterface $request = NULL);\n\n  /**\n   * Discovery controller callback.\n   *\n   * @param string $path\n   *   The requested path.\n   *\n   * @return array\n   *   The resource field collection with the discovery information.\n   */\n  public function discover($path = NULL);\n\n  /**\n   * Shorthand method to perform a quick GET request.\n   *\n   * @param string $path\n   *   The resource path.\n   * @param array $query\n   *   The parsed query string.\n   *\n   * @return array\n   *   The array ready for the formatter.\n   */\n  public function doGet($path = '', array $query = array());\n\n  /**\n   * Shorthand method to perform a quick POST request.\n   *\n   * @param array $parsed_body\n   *   The parsed body.\n   *\n   * @return array\n   *   The array ready for the formatter.\n   */\n  public function doPost(array $parsed_body);\n\n  /**\n   * Shorthand method to perform a quick PATCH request.\n   *\n   * @param string $path\n   *   The resource path.\n   * @param array $parsed_body\n   *   The parsed body.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *   When the path is not present.\n   *\n   * @return array\n   *   The array ready for the formatter.\n   */\n  public function doPatch($path, array $parsed_body);\n\n  /**\n   * Shorthand method to perform a quick PUT request.\n   *\n   * @param string $path\n   *   The resource path.\n   * @param array $parsed_body\n   *   The parsed body.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *   When the path is not present.\n   *\n   * @return array\n   *   The array ready for the formatter.\n   */\n  public function doPut($path, array $parsed_body);\n\n  /**\n   * Shorthand method to perform a quick DELETE request.\n   *\n   * @param string $path\n   *   The resource path.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   *   When the path is not present.\n   */\n  public function doDelete($path);\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/ResourceNode.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful\\Plugin\\resource\\ResourceNode.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\n\nclass ResourceNode extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::entityPreSave().\n   *\n   * Set the node author and other defaults.\n   */\n  public function entityPreSave(\\EntityMetadataWrapper $wrapper) {\n    $node = $wrapper->value();\n    if (!empty($node->nid)) {\n      // Node is already saved.\n      return;\n    }\n    node_object_prepare($node);\n    $node->uid = $this->getAccount()->uid;\n  }\n\n}\n"
  },
  {
    "path": "src/Plugin/resource/Users__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Plugin\\resource\\Users__1_0.\n */\n\nnamespace Drupal\\restful\\Plugin\\resource;\n\n/**\n * Class Articles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"users:1.0\",\n *   resource = \"users\",\n *   label = \"Users\",\n *   description = \"Export the User entity with cookie authentication.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"user\",\n *     \"bundles\": {\n *       \"user\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Users__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    // The mail will be shown only to the own user or privileged users.\n    $public_fields['mail'] = array(\n      'property' => 'mail',\n    );\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "src/RateLimit/Entity/RateLimit.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful\\RateLimit\\Entity\\RateLimit.\n */\n\nnamespace Drupal\\restful\\RateLimit\\Entity;\n\nclass RateLimit extends \\Entity {\n\n  /**\n   * Number of hits.\n   *\n   * @var int\n   */\n  public $hits = 0;\n\n  /**\n   * Expiration timestamp.\n   *\n   * @var int\n   */\n  public $expiration = 0;\n\n  /**\n   * Saves an extra hit.\n   */\n  public function hit() {\n    $this->hits++;\n    $this->save();\n  }\n\n  /**\n   * Checks if the entity is expired.\n   */\n  public function isExpired() {\n    return REQUEST_TIME > $this->expiration;\n  }\n\n}\n"
  },
  {
    "path": "src/RateLimit/Entity/RateLimitController.php",
    "content": "<?php\n\n/**\n * @file\n * Contains Drupal\\restful\\RateLimit\\Entity\\RateLimitController.\n */\n\nnamespace Drupal\\restful\\RateLimit\\Entity;\n\nclass RateLimitController extends \\EntityAPIController {}\n"
  },
  {
    "path": "src/RateLimit/RateLimitManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RateLimit\\RateLimitManager\n */\n\nnamespace Drupal\\restful\\RateLimit;\n\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\FloodException;\nuse Drupal\\restful\\Http\\HttpHeader;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\RateLimitPluginManager;\nuse Drupal\\restful\\Plugin\\rate_limit\\RateLimit;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\nclass RateLimitManager implements RateLimitManagerInterface {\n\n  const UNLIMITED_RATE_LIMIT = -1;\n\n  /**\n   * The identified user account for the request.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * Resource name being checked.\n   *\n   * @var string\n   */\n  protected $resource;\n\n  /**\n   * The rate limit plugins.\n   *\n   * @var RateLimitPluginCollection\n   */\n  protected $plugins;\n\n  /**\n   * Set the account.\n   *\n   * @param \\stdClass $account\n   */\n  public function setAccount($account) {\n    $this->account = $account;\n  }\n\n  /**\n   * Get the account.\n   *\n   * @return \\stdClass\n   *   The account object,\n   */\n  public function getAccount() {\n    return $this->account;\n  }\n\n  /**\n   * Constructor for RateLimitManager.\n   *\n   * @param ResourceInterface $resource\n   *   Resource being checked.\n   * @param array $plugin_options\n   *   Array of options keyed by plugin id.\n   * @param object $account\n   *   The identified user account for the request.\n   * @param RateLimitPluginManager $manager\n   *   The plugin manager.\n   */\n  public function __construct(ResourceInterface $resource, array $plugin_options, $account = NULL, RateLimitPluginManager $manager = NULL) {\n    $this->resource = $resource;\n    $account = $account ? $account : $resource->getAccount();\n    $this->account = $account ? $account : drupal_anonymous_user();\n    $manager = $manager ?: RateLimitPluginManager::create();\n    $options = array();\n    foreach ($plugin_options as $plugin_id => $rate_options) {\n      // Set the instance id to articles::request and specify the plugin id.\n      $instance_id = $resource->getResourceName() . PluginBase::DERIVATIVE_SEPARATOR . $plugin_id;\n      $options[$instance_id] = array(\n        'id' => $plugin_id,\n        'resource' => $resource,\n      );\n      $options[$instance_id] += $rate_options;\n    }\n    $this->plugins = new RateLimitPluginCollection($manager, $options);\n  }\n\n  /**\n   * Checks if the current request has reached the rate limit.\n   *\n   * If the user has reached the limit this method will throw an exception. If\n   * not, the hits counter will be updated for subsequent calls. Since the\n   * request can match multiple events, the access is only granted if all events\n   * are cleared.\n   *\n   * @param RequestInterface $request\n   *   The request array.\n   *\n   * @throws FloodException if the rate limit has been reached for the\n   * current request.\n   */\n  public function checkRateLimit(RequestInterface $request) {\n    $now = new \\DateTime();\n    $now->setTimestamp(REQUEST_TIME);\n    // Check all rate limits configured for this handler.\n    foreach ($this->plugins as $instance_id => $plugin) {\n      // If the limit is unlimited then skip everything.\n      /* @var RateLimit $plugin */\n      $limit = $plugin->getLimit($this->account);\n      $period = $plugin->getPeriod();\n      if ($limit == static::UNLIMITED_RATE_LIMIT) {\n        // User has unlimited access to the resources.\n        continue;\n      }\n      // If the current request matches the configured event then check if the\n      // limit has been reached.\n      if (!$plugin->isRequestedEvent($request)) {\n        continue;\n      }\n      if (!$rate_limit_entity = $plugin->loadRateLimitEntity($this->account)) {\n        // If there is no entity, then create one.\n        // We don't need to save it since it will be saved upon hit.\n        $rate_limit_entity = entity_create('rate_limit', array(\n          'timestamp' => REQUEST_TIME,\n          'expiration' => $now->add($period)->format('U'),\n          'hits' => 0,\n          'event' => $plugin->getPluginId(),\n          'identifier' => $plugin->generateIdentifier($this->account),\n        ));\n      }\n      // When the new rate limit period starts.\n      $new_period = new \\DateTime();\n      $new_period->setTimestamp($rate_limit_entity->expiration);\n      if ($rate_limit_entity->isExpired()) {\n        // If the rate limit has expired renew the timestamps and assume 0\n        // hits.\n        $rate_limit_entity->timestamp = REQUEST_TIME;\n        $rate_limit_entity->expiration = $now->add($period)->format('U');\n        $rate_limit_entity->hits = 0;\n        if ($limit == 0) {\n          $exception = new FloodException('Rate limit reached');\n          $exception->setHeader('Retry-After', $new_period->format(\\DateTime::RFC822));\n          throw $exception;\n        }\n      }\n      else {\n        if ($rate_limit_entity->hits >= $limit) {\n          $exception = new FloodException('Rate limit reached');\n          $exception->setHeader('Retry-After', $new_period->format(\\DateTime::RFC822));\n          throw $exception;\n        }\n      }\n      // Save a new hit after generating the exception to mitigate DoS attacks.\n      $rate_limit_entity->hit();\n\n      // Add the limit headers to the response.\n      $remaining = $limit == static::UNLIMITED_RATE_LIMIT ? 'unlimited' : $limit - ($rate_limit_entity->hits + 1);\n      $response = restful()->getResponse();\n      $headers = $response->getHeaders();\n      $headers->append(HttpHeader::create('X-Rate-Limit-Limit', $limit));\n      $headers->append(HttpHeader::create('X-Rate-Limit-Remaining', $remaining));\n      $time_remaining = $rate_limit_entity->expiration - REQUEST_TIME;\n      $headers->append(HttpHeader::create('X-Rate-Limit-Reset', $time_remaining));\n    }\n  }\n\n  /**\n   * Delete all expired rate limit entities.\n   */\n  public static function deleteExpired() {\n    // Clear the expired restful_rate_limit entries.\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', 'rate_limit')\n      ->propertyCondition('expiration', REQUEST_TIME, '>')\n      ->execute();\n    if (!empty($results['rate_limit'])) {\n      $rlids = array_keys($results['rate_limit']);\n      entity_delete_multiple('rate_limit', $rlids);\n    }\n  }\n\n}\n"
  },
  {
    "path": "src/RateLimit/RateLimitManagerInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RateLimit\\RateLimitManagerInterface\n */\n\nnamespace Drupal\\restful\\RateLimit;\n\nuse \\Drupal\\restful\\Exception\\FloodException;\nuse Drupal\\restful\\Http\\RequestInterface;\n\ninterface RateLimitManagerInterface {\n\n  /**\n   * Set the account.\n   *\n   * @param object $account\n   */\n  public function setAccount($account);\n\n  /**\n   * Get the account.\n   *\n   * @return object\n   *   The account object,\n   */\n  public function getAccount();\n\n  /**\n   * Checks if the current request has reached the rate limit.\n   *\n   * If the user has reached the limit this method will throw an exception. If\n   * not, the hits counter will be updated for subsequent calls. Since the\n   * request can match multiple events, the access is only granted if all events\n   * are cleared.\n   *\n   * @param RequestInterface $request\n   *   The request array.\n   *\n   * @throws FloodException if the rate limit has been reached for the\n   * current request.\n   */\n  public function checkRateLimit(RequestInterface $request);\n\n  /**\n   * Delete all expired rate limit entities.\n   */\n  public static function deleteExpired();\n\n}\n"
  },
  {
    "path": "src/RateLimit/RateLimitPluginCollection.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RateLimit\\RateLimitPluginCollection\n */\n\nnamespace Drupal\\restful\\RateLimit;\n\nuse Drupal\\Core\\Plugin\\DefaultLazyPluginCollection;\n\nclass RateLimitPluginCollection extends DefaultLazyPluginCollection {}\n"
  },
  {
    "path": "src/RenderCache/Entity/CacheFragment.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RenderCache\\Entity\\CacheFragment.\n */\n\nnamespace Drupal\\restful\\RenderCache\\Entity;\n\nclass CacheFragment extends \\Entity {\n\n  /**\n   * The identifier hash for the tag.\n   *\n   * @var string\n   */\n  public $hash;\n\n  /**\n   * Tag type.\n   *\n   * @var string\n   */\n  public $type;\n\n  /**\n   * Tag value.\n   *\n   * @var string\n   */\n  public $value;\n\n  /**\n   * The hash to be used as the cache ID.\n   *\n   * @return string\n   *   The hash.\n   */\n  public function getHash() {\n    return $this->hash;\n  }\n\n  /**\n   * The hash to be used as the cache ID.\n   *\n   * @param string $hash\n   *   The hash.\n   */\n  public function setHash($hash) {\n    $this->hash = $hash;\n  }\n\n  /**\n   * Get the type.\n   *\n   * @return string\n   *   The type.\n   */\n  public function getType() {\n    return $this->type;\n  }\n\n  /**\n   * Set the type.\n   *\n   * @param string $type\n   *   The type.\n   */\n  public function setType($type) {\n    $this->type = $type;\n  }\n\n  /**\n   * Get the value.\n   *\n   * @return string\n   *   The value.\n   */\n  public function getValue() {\n    return $this->value;\n  }\n\n  /**\n   * Set the value.\n   *\n   * @param string $value\n   *   The value.\n   */\n  public function setValue($value) {\n    $this->value = $value;\n  }\n\n}\n"
  },
  {
    "path": "src/RenderCache/Entity/CacheFragmentController.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController.\n */\n\nnamespace Drupal\\restful\\RenderCache\\Entity;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource;\n\n/**\n * Class CacheFragmentController.\n *\n * @package Drupal\\restful\\RenderCache\\Entity\n */\nclass CacheFragmentController extends \\EntityAPIController {\n\n  /**\n   * The type name of the cache fragment entity.\n   */\n  const ENTITY_TYPE = 'cache_fragment';\n\n  /**\n   * The name of the DB table holding the entities.\n   *\n   * @var string\n   */\n  protected static $tableName;\n\n  /**\n   * The name of the property that contains the ID of the entity.\n   *\n   * @var string\n   */\n  protected static $tableIdKey;\n\n  /**\n   * Creates all the caches tags from the tag collection.\n   *\n   * @param ArrayCollection $cache_fragments\n   *   The collection of tags.\n   *\n   * @return CacheFragment[]\n   *   An array of fragments.\n   */\n  public function createCacheFragments(ArrayCollection $cache_fragments) {\n    $hash = $this->generateCacheHash($cache_fragments);\n    if ($fragments = $this->existingFragments($hash)) {\n      return $fragments;\n    }\n    foreach ($cache_fragments as $tag_type => $tag_value) {\n      $cache_fragment = new CacheFragment(array(\n        'value' => $tag_value,\n        'type' => $tag_type,\n        'hash' => $hash,\n      ), static::ENTITY_TYPE);\n      try {\n        if ($id = $this->save($cache_fragment)) {\n          $fragments[] = $cache_fragment;\n        }\n      }\n      catch (\\Exception $e) {\n        // Log the exception. It's probably a duplicate fragment.\n        watchdog_exception('restful', $e);\n      }\n    }\n    return $fragments;\n  }\n\n  /**\n   * Gets the existing fragments for a given hash.\n   *\n   * @param string $hash\n   *   The hash.\n   *\n   * @return CacheFragment[]\n   *   An array of fragments.\n   */\n  protected function existingFragments($hash) {\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', static::ENTITY_TYPE)\n      ->propertyCondition('hash', $hash)\n      ->execute();\n    return empty($results[static::ENTITY_TYPE]) ? array() : $this->load(array_keys($results[static::ENTITY_TYPE]));\n  }\n\n  /**\n   * Generated the cache hash based on the cache fragments collection.\n   *\n   * @param ArrayCollection $cache_fragments\n   *   The collection of tags.\n   *\n   * @return string\n   *   The generated hash.\n   */\n  public function generateCacheHash(ArrayCollection $cache_fragments) {\n    return substr(sha1(serialize($cache_fragments->toArray())), 0, 40);\n  }\n\n  /**\n   * Gets the hashes for an EFQ.\n   *\n   * @param \\EntityFieldQuery $query\n   *   The EFQ.\n   *\n   * @return string[]\n   *   The hashes that meet the conditions.\n   */\n  public static function lookUpHashes(\\EntityFieldQuery $query) {\n    $results = $query->execute();\n    if (empty($results[static::ENTITY_TYPE])) {\n      return array();\n    }\n    $fragment_ids = array_keys($results[static::ENTITY_TYPE]);\n\n    $hashes = db_query('SELECT hash FROM {' . static::getTableName() . '} WHERE ' . static::getTableIdkey() . ' IN (:ids)', array(\n      ':ids' => $fragment_ids,\n    ))->fetchCol();\n    return $hashes;\n  }\n\n  /**\n   * Removes all the cache fragments.\n   */\n  public function wipe() {\n    // We are not truncating the entity table so hooks are fired.\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', static::ENTITY_TYPE)\n      ->execute();\n    if (empty($results[static::ENTITY_TYPE])) {\n      return;\n    }\n    if ($this->isFastDeleteEnabled()) {\n      db_truncate($this::getTableName())->execute();\n      return;\n    }\n    $this->delete(array_keys($results[static::ENTITY_TYPE]));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function delete($ids, \\DatabaseTransaction $transaction = NULL) {\n    if ($this->isFastDeleteEnabled()) {\n      $this->fastDelete($ids, $transaction);\n      return;\n    }\n    parent::delete($ids, $transaction);\n  }\n\n  /**\n   * Do a fast delete without loading entities of firing delete hooks.\n   *\n   * @param array $ids\n   *   An array of entity IDs.\n   * @param \\DatabaseTransaction $transaction\n   *   Optionally a DatabaseTransaction object to use. Allows overrides to pass\n   *   in their transaction object.\n   *\n   * @throws \\Exception\n   *   When there is a database error.\n   */\n  protected function fastDelete($ids, \\DatabaseTransaction $transaction = NULL) {\n    $transaction = isset($transaction) ? $transaction : db_transaction();\n\n    try {\n      db_delete($this::getTableName())\n        ->condition($this::getTableIdkey(), $ids, 'IN')\n        ->execute();\n\n      // Reset the cache as soon as the changes have been applied.\n      $this->resetCache($ids);\n\n      // Ignore slave server temporarily.\n      db_ignore_slave();\n    }\n    catch (\\Exception $e) {\n      $transaction->rollback();\n      watchdog_exception($this->entityType, $e);\n      throw $e;\n    }\n  }\n\n  /**\n   * Helper function that checks if this controller uses a fast delete.\n   *\n   * @return bool\n   *   TRUE if fast delete is enabled. FALSE otherwise.\n   */\n  protected function isFastDeleteEnabled() {\n    return (bool) variable_get('restful_fast_cache_clear', TRUE);\n  }\n\n  /**\n   * Get the resource ID for the selected hash.\n   *\n   * @param string $hash\n   *   The unique hash for the cache fragments.\n   *\n   * @return string\n   *   The resource ID.\n   */\n  public static function resourceIdFromHash($hash) {\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', static::ENTITY_TYPE)\n      ->propertyCondition('type', 'resource')\n      ->propertyCondition('hash', $hash)\n      ->range(0, 1)\n      ->execute();\n    if (empty($results[static::ENTITY_TYPE])) {\n      return NULL;\n    }\n    $cache_fragment = entity_load_single(static::ENTITY_TYPE, key($results[static::ENTITY_TYPE]));\n    $pos = strpos($cache_fragment->value, CacheDecoratedResource::CACHE_PAIR_SEPARATOR);\n    return $pos === FALSE ? $cache_fragment->value : substr($cache_fragment->value, 0, $pos);\n  }\n\n  /**\n   * Gets the name of the table for the cache fragment entity.\n   *\n   * @return string\n   *   The name.\n   */\n  protected static function getTableName() {\n    if (static::$tableName) {\n      return static::$tableName;\n    }\n    // Get the hashes from the base table.\n    $info = entity_get_info(static::ENTITY_TYPE);\n    static::$tableName = $info['base table'];\n    return static::$tableName;\n  }\n\n  /**\n   * Gets the name of the table for the cache fragment entity.\n   *\n   * @return string\n   *   The name.\n   */\n  protected static function getTableIdkey() {\n    if (static::$tableIdKey) {\n      return static::$tableIdKey;\n    }\n    // Get the hashes from the base table.\n    $info = entity_get_info(static::ENTITY_TYPE);\n    static::$tableIdKey = $info['entity keys']['id'];\n    return static::$tableIdKey;\n  }\n\n}\n"
  },
  {
    "path": "src/RenderCache/RenderCache.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RenderCache\\RenderCache.\n */\n\nnamespace Drupal\\restful\\RenderCache;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController;\n\n/**\n * Class RenderCache.\n *\n * @package Drupal\\restful\\RenderCache\n */\nclass RenderCache implements RenderCacheInterface {\n\n  /**\n   * Stores the default cache bin.\n   *\n   * @var string\n   */\n  const CACHE_BIN = 'cache_restful';\n\n  /**\n   * The hash for the cache id.\n   */\n  protected $hash;\n\n  /**\n   * The cache fragments.\n   *\n   * @var ArrayCollection\n   */\n  protected $cacheFragments;\n\n  /**\n   * The cache object.\n   *\n   * @var \\DrupalCacheInterface\n   */\n  protected $cacheObject;\n\n  /**\n   * Create an object of type RenderCache.\n   *\n   * @param ArrayCollection $cache_fragments\n   *   The cache fragments.\n   * @param string $hash\n   *   The hash for the cache object.\n   * @param \\DrupalCacheInterface $cache_object\n   *   The cache backend to use with this object.\n   */\n  public function __construct(ArrayCollection $cache_fragments, $hash, \\DrupalCacheInterface $cache_object) {\n    $this->cacheFragments = $cache_fragments;\n    /* @var CacheFragmentController $controller */\n    $controller = entity_get_controller('cache_fragment');\n    $this->hash = $hash ?: $controller->generateCacheHash($cache_fragments);\n    $this->cacheObject = $cache_object;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function create(ArrayCollection $cache_fragments, \\DrupalCacheInterface $cache_object) {\n    /* @var CacheFragmentController $controller */\n    $controller = entity_get_controller('cache_fragment');\n    return new static($cache_fragments, $controller->generateCacheHash($cache_fragments), $cache_object);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function get() {\n    $cid = $this->generateCacheId();\n    $query = new \\EntityFieldQuery();\n    $count = $query\n      ->entityCondition('entity_type', 'cache_fragment')\n      ->propertyCondition('hash', $cid)\n      ->count()\n      ->execute();\n\n    if ($count) {\n      return $this->cacheObject->get($cid);\n    }\n    // If there are no cache fragments for the given hash then clear the cache\n    // and return NULL.\n    $this->cacheObject->clear($cid);\n    return NULL;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($value) {\n    /* @var CacheFragmentController $controller */\n    $controller = entity_get_controller('cache_fragment');\n    if (!$controller->createCacheFragments($this->cacheFragments)) {\n      return;\n    }\n    $this->cacheObject->set($this->generateCacheId(), $value);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function clear() {\n    // Remove the cache.\n    $this->cacheObject->clear($this->generateCacheId());\n    // Delete all cache fragments for that hash.\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', 'cache_fragment')\n      ->propertyCondition('hash', $this->generateCacheId())\n      ->execute();\n    if (empty($results['cache_fragment'])) {\n      return;\n    }\n    // Delete the actual entities.\n    entity_delete_multiple('cache_fragment', array_keys($results['cache_fragment']));\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getCid() {\n    return $this->hash;\n  }\n\n  /**\n   * Generates the cache id based on the hash and the fragment IDs.\n   *\n   * @return string\n   *   The cid.\n   */\n  protected function generateCacheId() {\n    return $this->hash;\n  }\n\n}\n"
  },
  {
    "path": "src/RenderCache/RenderCacheInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RenderCache\\RenderCacheInterface.\n */\n\nnamespace Drupal\\restful\\RenderCache;\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController;\n\ninterface RenderCacheInterface {\n\n\n  /**\n   * Factory function to create a new RenderCacheInterface object.\n   *\n   * @param ArrayCollection $cache_fragments\n   *   The tags collection.\n   * @param \\DrupalCacheInterface $cache_object\n   *   The cache backend to use.\n   *\n   * @return RenderCacheInterface\n   *   The cache controller.\n   */\n  public static function create(ArrayCollection $cache_fragments, \\DrupalCacheInterface $cache_object);\n\n  /**\n   * Get the cache.\n   *\n   * @return mixed\n   *   The cache value.\n   */\n  public function get();\n\n  /**\n   * Set the cache.\n   *\n   * @param mixed $value\n   *   The value to cache.\n   */\n  public function set($value);\n\n  /**\n   * Clears the cache for the given cache object.\n   */\n  public function clear();\n\n  /**\n   * Get the cache ID (aka cache hash).\n   *\n   * @return string\n   *   The cache ID.\n   */\n  public function getCid();\n\n}\n"
  },
  {
    "path": "src/Resource/EnabledArrayIterator.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Resource\\EnabledArrayIterator.\n */\n\nnamespace Drupal\\restful\\Resource;\n\nclass EnabledArrayIterator extends \\FilterIterator {\n\n  /**\n   * Check whether the current element of the iterator is acceptable.\n   *\n   * @return bool\n   *   TRUE if the current element is acceptable, otherwise FALSE.\n   *\n   * @link http://php.net/manual/en/filteriterator.accept.php\n   */\n  public function accept() {\n    if (!$resource = $this->current()) {\n      return FALSE;\n    }\n    return $resource->isEnabled();\n  }\n\n}\n"
  },
  {
    "path": "src/Resource/ResourceManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Resource\\ResourceManager.\n */\n\nnamespace Drupal\\restful\\Resource;\n\nuse Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\nuse Drupal\\Component\\Plugin\\PluginBase;\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Exception\\UnauthorizedException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\ResourcePluginManager;\n\nclass ResourceManager implements ResourceManagerInterface {\n\n  /**\n   * The request object.\n   *\n   * @var RequestInterface\n   */\n  protected $request;\n\n  /**\n   * The plugin manager.\n   *\n   * @var ResourcePluginManager\n   */\n  protected $pluginManager;\n\n  /**\n   * The resource plugins.\n   *\n   * @var ResourcePluginCollection\n   */\n  protected $plugins;\n\n  /**\n   * Constructor for ResourceManager.\n   *\n   * @param RequestInterface $request\n   *   The request object.\n   * @param ResourcePluginManager $manager\n   *   The plugin manager.\n   */\n  public function __construct(RequestInterface $request, ResourcePluginManager $manager = NULL) {\n    $this->request = $request;\n    $this->pluginManager = $manager ?: ResourcePluginManager::create('cache', $request);\n    $options = array();\n    foreach ($this->pluginManager->getDefinitions() as $plugin_id => $plugin_definition) {\n      // Set the instance id to articles::1.5 (for example).\n      $options[$plugin_id] = $plugin_definition;\n    }\n    $this->plugins = new ResourcePluginCollection($this->pluginManager, $options);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPlugins($only_enabled = TRUE) {\n    if (!$only_enabled) {\n      return $this->plugins;\n    }\n    $cloned_plugins = clone $this->plugins;\n    $instance_ids = $cloned_plugins->getInstanceIds();\n    foreach ($instance_ids as $instance_id) {\n      $plugin = NULL;\n      try {\n        $plugin = $cloned_plugins->get($instance_id);\n      }\n      catch (UnauthorizedException $e) {}\n      if (!$plugin instanceof ResourceInterface) {\n        $cloned_plugins->remove($instance_id);\n        $cloned_plugins->removeInstanceId($instance_id);\n      }\n    }\n    return $cloned_plugins;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPlugin($instance_id, RequestInterface $request = NULL) {\n    /* @var ResourceInterface $plugin */\n    if (!$plugin = $this->plugins->get($instance_id)) {\n      return NULL;\n    }\n    if ($request) {\n      $plugin->setRequest($request);\n    }\n    return $plugin;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getPluginCopy($instance_id, RequestInterface $request = NULL) {\n    if (!$plugin = $this->pluginManager->createInstance($instance_id)) {\n      return NULL;\n    }\n    if ($request) {\n      $plugin->setRequest($request);\n    }\n    // Allow altering the resource, this way we can read the resource's\n    // definition to return a different class that is using composition.\n    drupal_alter('restful_resource', $plugin);\n    $plugin = $plugin->isEnabled() ? $plugin : NULL;\n    return $plugin;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function clearPluginCache($instance_id) {\n    $this->plugins->remove($instance_id);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceIdFromRequest() {\n    $resource_name = &drupal_static(__METHOD__);\n    if (isset($resource_name)) {\n      return $resource_name;\n    }\n    $path = $this->request->getPath(FALSE);\n    list($resource_name,) = static::getPageArguments($path);\n    return $resource_name;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getVersionFromRequest() {\n    $version = &drupal_static(__METHOD__);\n    if (isset($version)) {\n      return $version;\n    }\n    $version = $this->getVersionFromProvidedRequest($this->request);\n    return $version;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getVersionFromProvidedRequest(RequestInterface $request = NULL) {\n    $path = $request->getPath(FALSE);\n    list($resource_name, $version) = static::getPageArguments($path);\n    if (preg_match('/^v\\d+(\\.\\d+)?$/', $version)) {\n      $version = $this->parseVersionString($version, $resource_name);\n      return $version;\n    }\n\n    // If there is no version in the URL check the header.\n    if ($version_string = $this->request->getHeaders()->get('x-api-version')->getValueString()) {\n      $version = $this->parseVersionString($version_string, $resource_name);\n      return $version;\n    }\n\n    // If there is no version negotiation information return the latest version.\n    $version = $this->getResourceLastVersion($resource_name);\n    return $version;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function negotiate() {\n    return $this->negotiateFromRequest($this->request);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function negotiateFromRequest(RequestInterface $request) {\n    $version = $this->getVersionFromProvidedRequest($request);\n    list($resource_name,) = static::getPageArguments($request->getPath(FALSE));\n    try {\n      $resource = $this->getPlugin($resource_name . PluginBase::DERIVATIVE_SEPARATOR . $version[0] . '.' . $version[1]);\n      return $resource->isEnabled() ? $resource : NULL;\n    }\n    catch (PluginNotFoundException $e) {\n      throw new ServerConfigurationException($e->getMessage());\n    }\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function executeCallback($callback, array $params = array()) {\n    if (!is_callable($callback)) {\n      if (is_array($callback) && count($callback) == 2 && is_array($callback[1])) {\n        // This code deals with the third scenario in the docblock. Get the\n        // callback and the parameters from the array, merge the parameters with\n        // the existing ones and call recursively to reuse the logic for the\n        // other cases.\n        return static::executeCallback($callback[0], array_merge($params, $callback[1]));\n      }\n      $callback_name = is_array($callback) ? $callback[1] : $callback;\n      throw new ServerConfigurationException(\"Callback function: $callback_name does not exist.\");\n    }\n\n    return call_user_func_array($callback, $params);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function isValidCallback($callback) {\n    // Valid callbacks are:\n    //   - 'function_name'\n    //   - 'SomeClass::someStaticMethod'\n    //   - array('function_name', array('param1', 2))\n    //   - array($this, 'methodName')\n    //   - array(array($this, 'methodName'), array('param1', 2))\n    if (!is_callable($callback)) {\n      if (is_array($callback) && count($callback) == 2 && is_array($callback[1])) {\n        return static::isValidCallback($callback[0]);\n      }\n      return FALSE;\n    }\n    return TRUE;\n  }\n\n  /**\n   * Get the resource name and version from the page arguments in the router.\n   *\n   * @param string $path\n   *   The path to match the router item. Leave it empty to use the current one.\n   *\n   * @return array\n   *   An array of 2 elements with the page arguments.\n   */\n  protected static function getPageArguments($path = NULL) {\n    $router_item = static::getMenuItem($path);\n    $output = array(NULL, NULL);\n    if (empty($router_item['page_arguments'])) {\n      return $output;\n    }\n    $page_arguments = $router_item['page_arguments'];\n\n    $index = 0;\n    foreach ($page_arguments as $page_argument) {\n      $output[$index] = $page_argument;\n      $index++;\n      if ($index >= 2) {\n        break;\n      }\n    }\n\n    return $output;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getPageCallback($path = NULL) {\n    $router_item = static::getMenuItem($path);\n    return isset($router_item['page_callback']) ? $router_item['page_callback'] : NULL;\n  }\n\n  /**\n   * Parses the version string.\n   *\n   * @param string $version\n   *   The string containing the version information.\n   * @param string $resource_name\n   *   (optional) Name of the resource to get the latest minor version.\n   *\n   * @return array\n   *   Numeric array with major and minor version.\n   */\n  protected function parseVersionString($version, $resource_name = NULL) {\n    if (preg_match('/^v\\d+(\\.\\d+)?$/', $version)) {\n      // Remove the leading 'v'.\n      $version = substr($version, 1);\n    }\n    $output = explode('.', $version);\n    if (count($output) == 1) {\n      $major_version = $output[0];\n      // Abort if the version is not numeric.\n      if (!$resource_name || !ctype_digit((string) $major_version)) {\n        return NULL;\n      }\n      // Get the latest version for the resource.\n      return $this->getResourceLastVersion($resource_name, $major_version);\n    }\n    // Abort if any of the versions is not numeric.\n    if (!ctype_digit((string) $output[0]) || !ctype_digit((string) $output[1])) {\n      return NULL;\n    }\n    return $output;\n  }\n\n  /**\n   * Get the non translated menu item.\n   *\n   * @param string $path\n   *   The path to match the router item. Leave it empty to use the current one.\n   *\n   * @return array\n   *   The page arguments.\n   *\n   * @see menu_get_item()\n   */\n  protected static function getMenuItem($path = NULL) {\n    $router_items = &drupal_static(__METHOD__);\n    if (!isset($path)) {\n      $path = $_GET['q'];\n    }\n    if (!isset($router_items[$path])) {\n      $original_map = arg(NULL, $path);\n\n      $parts = array_slice($original_map, 0, MENU_MAX_PARTS);\n      $ancestors = menu_get_ancestors($parts);\n      $router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' => $ancestors))->fetchAssoc();\n\n      if ($router_item) {\n        // Allow modules to alter the router item before it is translated and\n        // checked for access.\n        drupal_alter('menu_get_item', $router_item, $path, $original_map);\n\n        $router_item['original_map'] = $original_map;\n        if ($original_map === FALSE) {\n          $router_items[$path] = FALSE;\n          return FALSE;\n        }\n        $router_item['map'] = $original_map;\n        $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $original_map), array_slice($original_map, $router_item['number_parts']));\n        $router_item['theme_arguments'] = array_merge(menu_unserialize($router_item['theme_arguments'], $original_map), array_slice($original_map, $router_item['number_parts']));\n      }\n      $router_items[$path] = $router_item;\n    }\n    return $router_items[$path];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getResourceLastVersion($resource_name, $major_version = NULL) {\n    $resources = array();\n    // Get all the resources corresponding to the resource name.\n    foreach ($this->pluginManager->getDefinitions() as $plugin_id => $plugin_definition) {\n      if ($plugin_definition['resource'] != $resource_name || (isset($major_version) && $plugin_definition['majorVersion'] != $major_version)) {\n        continue;\n      }\n      $resources[$plugin_definition['majorVersion']][$plugin_definition['minorVersion']] = $plugin_definition;\n    }\n    // Sort based on the major version.\n    ksort($resources, SORT_NUMERIC);\n    // Get a list of resources for the latest major version.\n    $resources = end($resources);\n    if (empty($resources)) {\n      return  NULL;\n    }\n    // Sort based on the minor version.\n    ksort($resources, SORT_NUMERIC);\n    // Get the latest resource for the minor version.\n    $resource = end($resources);\n    return array($resource['majorVersion'], $resource['minorVersion']);\n  }\n\n}\n"
  },
  {
    "path": "src/Resource/ResourceManagerInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Resource\\ResourceManagerInterface.\n */\n\nnamespace Drupal\\restful\\Resource;\n\nuse \\Drupal\\restful\\Exception\\RestfulException;\nuse \\Drupal\\restful\\Exception\\ServerConfigurationException;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse \\Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse \\Drupal\\Component\\Plugin\\Exception\\PluginNotFoundException;\n\ninterface ResourceManagerInterface {\n\n  /**\n   * Gets the plugin collection for this plugin manager.\n   *\n   * @param bool $only_enabled\n   *   Only get the enabled resources. Defaults to TRUE.\n   *\n   * @return ResourcePluginCollection\n   *   The plugin collection.\n   */\n  public function getPlugins($only_enabled = TRUE);\n\n  /**\n   * Get a resource plugin instance by instance ID.\n   *\n   * @param string $instance_id\n   *   The instance ID.\n   * @param RequestInterface $request\n   *   The request object.\n   *\n   * @return ResourceInterface\n   *   The plugin.\n   *\n   * @throws PluginNotFoundException\n   *   If the plugin instance cannot be found.\n   */\n  public function getPlugin($instance_id, RequestInterface $request = NULL);\n\n  /**\n   * Clears the static cache version of the plugin.\n   *\n   * @param string $instance_id\n   *   Instance ID of the plugin.\n   */\n  public function clearPluginCache($instance_id);\n\n  /**\n   * Get the resource name for the current request.\n   *\n   * @return string\n   *   The resource ID.\n   */\n  public function getResourceIdFromRequest();\n\n  /**\n   * Gets the major and minor version for the current request.\n   *\n   * @return array\n   *   The array with the version.\n   */\n  public function getVersionFromRequest();\n\n  /**\n   * Gets the major and minor version for the provided request.\n   *\n   * @param \\Drupal\\restful\\Http\\RequestInterface $request\n   *   The request object to get the version from. If NULL the current request\n   *   will be used.\n   *\n   * @return array\n   *   The array with the version.\n   */\n  public function getVersionFromProvidedRequest(RequestInterface $request);\n\n  /**\n   * Gets the resource plugin based on the information in the request object.\n   *\n   * @throws ServerConfigurationException\n   *   If the plugin could not be found.\n   *\n   * @return ResourceInterface\n   *   The resource plugin instance.\n   */\n  public function negotiate();\n\n  /**\n   * Gets the resource plugin based on the information in the request object.\n   *\n   * @param \\Drupal\\restful\\Http\\RequestInterface $request\n   *   The request object to get the version from. If NULL the current request\n   *   will be used.\n   *\n   * @throws ServerConfigurationException\n   *   If the plugin could not be found.\n   *\n   * @return ResourceInterface\n   *   The resource plugin instance.\n   */\n  public function negotiateFromRequest(RequestInterface $request);\n\n  /**\n   * Execute a user callback.\n   *\n   * @param mixed $callback\n   *   There are 3 ways to define a callback:\n   *     - String with a function name. Ex: 'drupal_map_assoc'.\n   *     - An array containing an object and a method name of that object.\n   *       Ex: array($this, 'format').\n   *     - An array containing any of the methods before and an array of\n   *       parameters to pass to the callback.\n   *       Ex: array(array($this, 'processing'), array('param1', 2))\n   * @param array $params\n   *   Array of additional parameters to pass in.\n   *\n   * @return mixed\n   *   The return value of the callback.\n   *\n   * @throws RestfulException\n   */\n  public static function executeCallback($callback, array $params = array());\n\n  /**\n   * Determine if a callback is valid.\n   *\n   * @param mixed $callback\n   *   There are 3 ways to define a callback:\n   *     - String with a function name. Ex: 'drupal_map_assoc'.\n   *     - An array containing an object and a method name of that object.\n   *       Ex: array($this, 'format').\n   *     - An array containing any of the methods before and an array of\n   *       parameters to pass to the callback.\n   *       Ex: array(array($this, 'processing'), array('param1', 2))\n   *\n   * @return bool\n   *   TRUE if the provided callback can be used in static::executeCallback.\n   */\n  public static function isValidCallback($callback);\n\n  /**\n   * Return the last version for a given resource.\n   *\n   * @param string $resource_name\n   *   The name of the resource.\n   * @param int $major_version\n   *   Get the last version for this major version. If NULL the last major\n   *   version for the resource will be used.\n   *\n   * @return array\n   *   Array containing the majorVersion and minorVersion.\n   */\n  public function getResourceLastVersion($resource_name, $major_version = NULL);\n\n  /**\n   * Get the menu item callback.\n   *\n   * @param string $path\n   *   The path to match the router item. Leave it empty to use the current one.\n   *\n   * @return string\n   *   The callback function to be executed.\n   */\n  public static function getPageCallback($path = NULL);\n\n  /**\n   * Get a copy of resource plugin instance by instance ID.\n   *\n   * This is useful when you have sub-requests, since you don't want to change\n   * state to other resources.\n   *\n   * @param string $instance_id\n   *   The instance ID.\n   * @param RequestInterface $request\n   *   The request object.\n   *\n   * @return ResourceInterface\n   *   The plugin.\n   *\n   * @throws PluginNotFoundException\n   *   If the plugin instance cannot be found.\n   */\n  public function getPluginCopy($instance_id, RequestInterface $request = NULL);\n\n}\n"
  },
  {
    "path": "src/Resource/ResourcePluginCollection.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Resource\\ResourcePluginCollection\n */\n\nnamespace Drupal\\restful\\Resource;\n\nuse Drupal\\Core\\Plugin\\DefaultLazyPluginCollection;\n\nclass ResourcePluginCollection extends DefaultLazyPluginCollection {\n\n  /**\n   * The key within the plugin configuration that contains the plugin ID.\n   *\n   * @var string\n   */\n  protected $pluginKey = 'name';\n\n  /**\n   * Overwrites LazyPluginCollection::get().\n   */\n  public function &get($instance_id) {\n    /* @var \\Drupal\\restful\\Plugin\\resource\\ResourceInterface $resource */\n    $resource = parent::get($instance_id);\n\n    // Allow altering the resource, this way we can read the resource's\n    // definition to return a different class that is using composition.\n    drupal_alter('restful_resource', $resource);\n    $resource = $resource->isEnabled() ? $resource : NULL;\n    return $resource;\n  }\n\n}\n"
  },
  {
    "path": "src/RestfulManager.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\RestfulManager.\n */\n\nnamespace Drupal\\restful;\n\nuse Drupal\\restful\\Formatter\\FormatterManager;\nuse Drupal\\restful\\Formatter\\FormatterManagerInterface;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Http\\Response;\nuse Drupal\\restful\\Http\\ResponseInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\RenderCache\\RenderCache;\nuse Drupal\\restful\\Resource\\ResourceManager;\nuse Drupal\\restful\\Resource\\ResourceManagerInterface;\nuse Drupal\\restful\\Util\\PersistableCache;\nuse Drupal\\restful\\Util\\PersistableCacheInterface;\n\nclass RestfulManager {\n\n  /**\n   * The front controller callback function.\n   */\n  const FRONT_CONTROLLER_CALLBACK = 'restful_menu_process_callback';\n\n  /**\n   * The front controller access callback function.\n   */\n  const FRONT_CONTROLLER_ACCESS_CALLBACK = 'restful_menu_access_callback';\n\n  /**\n   * The request object.\n   *\n   * @var RequestInterface\n   */\n  protected $request;\n\n  /**\n   * The response object.\n   *\n   * @var ResponseInterface\n   */\n  protected $response;\n\n  /**\n   * The resource manager.\n   *\n   * @var ResourceManagerInterface\n   */\n  protected $resourceManager;\n\n  /**\n   * The formatter manager.\n   *\n   * @var FormatterManagerInterface\n   */\n  protected $formatterManager;\n\n  /**\n   * The persistable cache global.\n   *\n   * @var PersistableCacheInterface\n   */\n  protected $persistableCache;\n\n  /**\n   * Accessor for the request.\n   *\n   * @return RequestInterface\n   *   The request object.\n   */\n  public function getRequest() {\n    return clone $this->request;\n  }\n\n  /**\n   * Mutator for the request.\n   *\n   * @param RequestInterface $request\n   *   The request object.\n   */\n  public function setRequest(RequestInterface $request) {\n    $this->request = $request;\n  }\n\n  /**\n   * Accessor for the response.\n   *\n   * @return ResponseInterface\n   *   The response object.\n   */\n  public function getResponse() {\n    return clone $this->response;\n  }\n\n  /**\n   * Mutator for the response.\n   *\n   * @param ResponseInterface $response\n   *   The response object.\n   */\n  public function setResponse(ResponseInterface $response) {\n    $this->response = $response;\n  }\n\n  /**\n   * Accessor for the resource manager.\n   *\n   * @return ResourceManagerInterface\n   */\n  public function getResourceManager() {\n    return clone $this->resourceManager;\n  }\n\n  /**\n   * Mutator for the resource manager.\n   *\n   * @param ResourceManagerInterface $resource_manager\n   */\n  public function setResourceManager(ResourceManagerInterface $resource_manager) {\n    $this->resourceManager = $resource_manager;\n  }\n\n  /**\n   * Accessor for the formatter manager.\n   *\n   * @return FormatterManagerInterface\n   */\n  public function getFormatterManager() {\n    return clone $this->formatterManager;\n  }\n\n  /**\n   * Mutator for the formatter manager.\n   *\n   * @param FormatterManagerInterface $formatter_manager\n   */\n  public function setFormatterManager(FormatterManagerInterface $formatter_manager) {\n    $this->formatterManager = $formatter_manager;\n  }\n\n  /**\n   * @return PersistableCacheInterface\n   */\n  public function getPersistableCache() {\n    return $this->persistableCache;\n  }\n\n  /**\n   * @param PersistableCacheInterface $persistable_cache\n   */\n  public function setPersistableCache($persistable_cache) {\n    $this->persistableCache = $persistable_cache;\n  }\n\n  /**\n   * Constructor.\n   */\n  public function __construct(RequestInterface $request, ResponseInterface $response, ResourceManagerInterface $resource_manager, FormatterManagerInterface $formatter_manager, PersistableCacheInterface $persistable_cache) {\n    // Init the properties.\n    $this->request = $request;\n    $this->response = $response;\n    $this->resourceManager = $resource_manager;\n    $this->formatterManager = $formatter_manager;\n    $this->persistableCache = $persistable_cache;\n  }\n\n  /**\n   * Factory method.\n   *\n   * @return RestfulManager\n   *   The newly created manager.\n   */\n  public static function createFromGlobals() {\n    $request = Request::createFromGlobals();\n    $response = Response::create();\n    $resource_manager = new ResourceManager($request);\n    $formatter_manager = new FormatterManager();\n    $persistable_cache = new PersistableCache(RenderCache::CACHE_BIN);\n\n    return new static($request, $response, $resource_manager, $formatter_manager, $persistable_cache);\n  }\n\n  /**\n   * Processes the request to produce a response.\n   *\n   * @return Response\n   *   The response being sent back to the consumer via the menu callback.\n   */\n  public function process() {\n    // Gets the appropriate resource plugin (based on the request object). That\n    // plugin processes the request according to the REST principles.\n    $data = $this->resourceManager->process();\n\n    // Formats the data based on the negotiatied output format. It accesses to\n    // the request information via the service container.\n    $body = $this->formatterManager->format($data);\n\n    // Prepares the body for the response. At this point all headers have been\n    // added to the response.\n    $this->response->setContent($body);\n\n    // The menu callback function is in charge of adding all the headers and\n    // returning the body.\n    return $this->response;\n  }\n\n  /**\n   * Checks if the passed in request belongs to RESTful.\n   *\n   * @param RequestInterface $request\n   *   The path to check.\n   *\n   * @return bool\n   *   TRUE if the path belongs to RESTful.\n   */\n  public static function isRestfulPath(RequestInterface $request) {\n    return ResourceManager::getPageCallback($request->getPath(FALSE)) == static::FRONT_CONTROLLER_CALLBACK;\n  }\n\n  /**\n   * Helper function to echo static strings.\n   *\n   * @param DataInterpreterInterface $value\n   *   The resource value.\n   * @param mixed $message\n   *   The string to relay.\n   *\n   * @return mixed\n   *   Returns $message\n   */\n  public static function echoMessage(DataInterpreterInterface $value, $message) {\n    return $message;\n  }\n\n}\n"
  },
  {
    "path": "src/Util/EntityFieldQuery.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\EntityFieldQuery.\n */\n\nnamespace Drupal\\restful\\Util;\n\nuse Drupal\\restful\\Exception\\ServerConfigurationException;\nuse SelectQuery;\n\nclass EntityFieldQuery extends \\EntityFieldQuery implements EntityFieldQueryRelationalConditionsInterface {\n\n  /**\n   * The relational filters.\n   *\n   * @var array[]\n   */\n  protected $relationships = array();\n\n  /**\n   * List of operators that require a LEFT JOIN instead of an INNER JOIN.\n   *\n   * @var array\n   */\n  protected static $leftJoinOperators = array(\n    'NOT IN',\n    'IS NULL',\n    'IS NOT NULL',\n    '<>',\n    'NOT BETWEEN',\n    'NOT LIKE',\n  );\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getRelationships() {\n    return $this->relationships;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function addRelationship(array $relational_filter) {\n    $this->relationships[] = $relational_filter;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function queryCallback() {\n    // Scan all the field conditions to see if there is any operator that needs\n    // a left join. If there is none, use the default behavior.\n    $left_field_conditions = array_filter($this->fieldConditions, function ($field_condition) {\n      return !empty($field_condition['operator']) && in_array($field_condition['operator'], static::$leftJoinOperators);\n    });\n    return empty($left_field_conditions) ? parent::queryCallback() : array($this, 'buildQuery');\n  }\n\n  /**\n   * Builds the SelectQuery and executes finishQuery().\n   */\n  protected function buildQuery() {\n    // Make the query be based on the entity table so we can get all the\n    // entities.\n    $select_query = $this->prePropertyQuery();\n    list($select_query, $id_key) = $this->fieldStorageQuery($select_query);\n    return $this->finishQuery($select_query, $id_key);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function finishQuery($select_query, $id_key = 'entity_id') {\n    $entity_type = $this->entityConditions['entity_type']['value'];\n    foreach ($this->getRelationships() as $delta => $relationship) {\n      // A relational filter consists of a chain of relationships and a value\n      // for a condition at the end.\n      // Relationships start with the entity base table.\n      $entity_info = entity_get_info($entity_type);\n      $entity_table = $entity_table_alias = $entity_info['base table'];\n\n      // Add the table if the base entity table was not added because:\n      // 1. There was a fieldCondition or fieldOrderBy, AND\n      // 2. There was no property condition or order.\n      if ($delta == 0) {\n        $is_entity_table_present = FALSE;\n        $field_base_table_alias = NULL;\n        foreach ($select_query->getTables() as $table_info) {\n          // Search for the base table and check if the entity table is present\n          // for the resource's entity type.\n          if (!$field_base_table_alias && empty($table_info['join type'])) {\n            $field_base_table_alias = $table_info['alias'];\n          }\n          if ($table_info['table'] == $entity_table) {\n            $is_entity_table_present = TRUE;\n            break;\n          }\n        }\n        if (!$is_entity_table_present && $field_base_table_alias) {\n          // We have the base table and we need to join it to the entity table.\n          _field_sql_storage_query_join_entity($select_query, $entity_type, $field_base_table_alias);\n        }\n      }\n      // Pop the last item, since it is the one that has to match the filter and\n      // will have the WHERE associated.\n      $condition = array_pop($relationship['relational_filters']);\n      foreach ($relationship['relational_filters'] as $relational_filter) {\n        /* @var RelationalFilterInterface $relational_filter */\n        if ($relational_filter->getType() == RelationalFilterInterface::TYPE_FIELD) {\n          $field_table_name = _field_sql_storage_tablename(field_info_field($relational_filter->getName()));\n          $field_table_alias = $this::aliasJoinTable($field_table_name, $select_query);\n          $select_query->addJoin('INNER', $field_table_name, $field_table_alias, sprintf('%s.%s = %s.%s',\n            $entity_table_alias,\n            $entity_info['entity keys']['id'],\n            $field_table_alias,\n            $id_key\n          ));\n          // Get the entity type being referenced.\n          $entity_info = entity_get_info($relational_filter->getEntityType());\n          $entity_table_alias = $this::aliasJoinTable($entity_info['base table'], $select_query);\n          $select_query->addJoin('INNER', $entity_info['base table'], $entity_table_alias, sprintf('%s.%s = %s.%s',\n            $field_table_name,\n            _field_sql_storage_columnname($relational_filter->getName(), $relational_filter->getColumn()),\n            $entity_table_alias,\n            $relational_filter->getTargetColumn()\n          ));\n        }\n        elseif ($relational_filter->getType() == RelationalFilterInterface::TYPE_PROPERTY) {\n          // In this scenario we want to join with the new table entity. This\n          // will only work if the property contains the referenced entity ID\n          // (which is not unreasonable).\n          $host_entity_table = $entity_table_alias;\n          $entity_info = entity_get_info($relational_filter->getEntityType());\n          $entity_table_alias = $this::aliasJoinTable($entity_info['base table'], $select_query);\n          $select_query->addJoin('INNER', $entity_info['base table'], $entity_table_alias, sprintf('%s.%s = %s.%s',\n            $host_entity_table,\n            $relational_filter->getName(),\n            $entity_table_alias,\n            $relational_filter->getTargetColumn()\n          ));\n        }\n      }\n      /* @var RelationalFilterInterface $condition */\n      if ($condition->getType() == RelationalFilterInterface::TYPE_FIELD) {\n        // Make the join to the filed table for the condition.\n        $field_table_name = _field_sql_storage_tablename(field_info_field($condition->getName()));\n        $field_column = _field_sql_storage_columnname($condition->getName(), $condition->getColumn());\n        $field_table_alias = $this::aliasJoinTable($field_table_name, $select_query);\n        $select_query->addJoin('INNER', $field_table_name, $field_table_alias, sprintf('%s.%s = %s.%s',\n          $entity_table_alias,\n          $entity_info['entity keys']['id'],\n          $field_table_alias,\n          $id_key\n        ));\n        if (in_array($relationship['operator'], array('IN', 'BETWEEN'))) {\n          $select_query->condition($field_table_name . '.' . $field_column, $relationship['value'], $relationship['operator'][0]);\n        }\n        else {\n          for ($index = 0; $index < count($relationship['value']); $index++) {\n            $select_query->condition($field_table_name . '.' . $field_column, $relationship['value'][$index], $relationship['operator'][$index]);\n          }\n        }\n      }\n      elseif ($condition->getType() == RelationalFilterInterface::TYPE_PROPERTY) {\n        if (in_array($relationship['operator'], array('IN', 'BETWEEN'))) {\n          $select_query->condition($entity_table_alias . '.' . $condition->getName(), $relationship['value'], $relationship['operator'][0]);\n        }\n        else {\n          for ($index = 0; $index < count($relationship['value']); $index++) {\n            $select_query->condition($entity_table_alias . '.' . $condition->getName(), $relationship['value'][$index], $relationship['operator'][$index]);\n          }\n        }\n      }\n    }\n    return parent::finishQuery($select_query, $id_key);\n  }\n\n  /**\n   * Helper function tha checks if the select query already has a join.\n   *\n   * @param string $table_name\n   *   The name of the table.\n   * @param SelectQuery $query\n   *   The query.\n   *\n   * @return string\n   *   The table alias.\n   */\n  protected static function aliasJoinTable($table_name, SelectQuery $query) {\n    foreach ($query->getTables() as $table_info) {\n      if ($table_info['alias'] == $table_name) {\n        $matches = array();\n        preg_match('/.*_(\\d+)$/', $table_name, $matches);\n        $num = empty($matches[1]) ? -1 : $matches[1];\n        return static::aliasJoinTable($table_name . '_' . ($num + 1), $query);\n      }\n    }\n    return $table_name;\n  }\n\n  /**\n   * Copy of propertyQuery() without the finishQuery execution.\n   *\n   * @see \\EntityFieldQuery::propertyQuery()\n   */\n  protected function prePropertyQuery() {\n    if (empty($this->entityConditions['entity_type'])) {\n      throw new \\EntityFieldQueryException(t('For this query an entity type must be specified.'));\n    }\n    $entity_type = $this->entityConditions['entity_type']['value'];\n    $entity_info = entity_get_info($entity_type);\n    if (empty($entity_info['base table'])) {\n      throw new \\EntityFieldQueryException(t('Entity %entity has no base table.', array('%entity' => $entity_type)));\n    }\n    $base_table = $entity_info['base table'];\n    $base_table_schema = drupal_get_schema($base_table);\n    $select_query = db_select($base_table);\n    $select_query->addExpression(':entity_type', 'entity_type', array(':entity_type' => $entity_type));\n    // Process the property conditions.\n    foreach ($this->propertyConditions as $property_condition) {\n      $this->addCondition($select_query, $base_table . '.' . $property_condition['column'], $property_condition);\n    }\n    // Process the four possible entity condition.\n    // The id field is always present in entity keys.\n    $sql_field = $entity_info['entity keys']['id'];\n    $this->addMetaData('base_table', $base_table);\n    $this->addMetaData('entity_id_key', $sql_field);\n    $id_map['entity_id'] = $sql_field;\n    $select_query->addField($base_table, $sql_field, 'entity_id');\n    if (isset($this->entityConditions['entity_id'])) {\n      $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['entity_id']);\n    }\n\n    // If there is a revision key defined, use it.\n    if (!empty($entity_info['entity keys']['revision'])) {\n      $sql_field = $entity_info['entity keys']['revision'];\n      $select_query->addField($base_table, $sql_field, 'revision_id');\n      if (isset($this->entityConditions['revision_id'])) {\n        $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['revision_id']);\n      }\n    }\n    else {\n      $sql_field = 'revision_id';\n      $select_query->addExpression('NULL', 'revision_id');\n    }\n    $id_map['revision_id'] = $sql_field;\n\n    // Handle bundles.\n    if (!empty($entity_info['entity keys']['bundle'])) {\n      $sql_field = $entity_info['entity keys']['bundle'];\n      $having = FALSE;\n\n      if (!empty($base_table_schema['fields'][$sql_field])) {\n        $select_query->addField($base_table, $sql_field, 'bundle');\n      }\n    }\n    else {\n      $sql_field = 'bundle';\n      $select_query->addExpression(':bundle', 'bundle', array(':bundle' => $entity_type));\n      $having = TRUE;\n    }\n    $id_map['bundle'] = $sql_field;\n    if (isset($this->entityConditions['bundle'])) {\n      if (!empty($entity_info['entity keys']['bundle'])) {\n        $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['bundle'], $having);\n      }\n      else {\n        // This entity has no bundle, so invalidate the query.\n        $select_query->where('1 = 0');\n      }\n    }\n\n    // Order the query.\n    foreach ($this->order as $order) {\n      if ($order['type'] == 'entity') {\n        $key = $order['specifier'];\n        if (!isset($id_map[$key])) {\n          throw new \\EntityFieldQueryException(t('Do not know how to order on @key for @entity_type', array('@key' => $key, '@entity_type' => $entity_type)));\n        }\n        $select_query->orderBy($id_map[$key], $order['direction']);\n      }\n      elseif ($order['type'] == 'property') {\n        $select_query->orderBy($base_table . '.' . $order['specifier'], $order['direction']);\n      }\n    }\n\n    return $select_query;\n  }\n\n  /**\n   * Copies field_sql_storage_field_storage_query() using left joins some times.\n   *\n   * @see field_sql_storage_field_storage_query()\n   */\n  protected function fieldStorageQuery(SelectQuery $select_query) {\n    if ($this->age == FIELD_LOAD_CURRENT) {\n      $tablename_function = '_field_sql_storage_tablename';\n      $id_key = 'entity_id';\n    }\n    else {\n      $tablename_function = '_field_sql_storage_revision_tablename';\n      $id_key = 'revision_id';\n    }\n    $table_aliases = array();\n    $query_tables = NULL;\n    $base_table = $this->metaData['base_table'];\n\n    // Add tables for the fields used.\n    $field_base_table = NULL;\n    foreach ($this->fields as $key => $field) {\n      $tablename = $tablename_function($field);\n      $table_alias = _field_sql_storage_tablealias($tablename, $key, $this);\n      $table_aliases[$key] = $table_alias;\n      $select_query->addMetaData('base_table', $base_table);\n      $entity_id_key = $this->metaData['entity_id_key'];\n      if ($field_base_table) {\n        if (!isset($query_tables[$table_alias])) {\n          $this->addFieldJoin($select_query, $field['field_name'], $tablename, $table_alias, \"$table_alias.entity_type = $field_base_table.entity_type AND $table_alias.$id_key = $field_base_table.$id_key\");\n        }\n      }\n      else {\n        // By executing prePropertyQuery() we made sure that the base table is\n        // the entity table.\n        $this->addFieldJoin($select_query, $field['field_name'], $tablename, $table_alias, \"$base_table.$entity_id_key = $table_alias.$id_key\");\n        // Store a reference to the list of joined tables.\n        $query_tables =& $select_query->getTables();\n        // Allow queries internal to the Field API to opt out of the access\n        // check, for situations where the query's results should not depend on\n        // the access grants for the current user.\n        if (!isset($this->tags['DANGEROUS_ACCESS_CHECK_OPT_OUT'])) {\n          $select_query->addTag('entity_field_access');\n        }\n        if (!$this->containsLeftJoinOperator($this->fields[$key]['field_name'])) {\n          $field_base_table = $table_alias;\n        }\n      }\n      if ($field['cardinality'] != 1 || $field['translatable']) {\n        $select_query->distinct();\n      }\n    }\n\n    // Add field conditions. We need a fresh grouping cache.\n    drupal_static_reset('_field_sql_storage_query_field_conditions');\n    _field_sql_storage_query_field_conditions($this, $select_query, $this->fieldConditions, $table_aliases, '_field_sql_storage_columnname');\n\n    // Add field meta conditions.\n    _field_sql_storage_query_field_conditions($this, $select_query, $this->fieldMetaConditions, $table_aliases, '_field_sql_storage_query_columnname');\n\n    // If there was no field condition that created an INNER JOIN, that means\n    // that additional JOINs need to carry the OR condition. For the base table\n    // we'll use the table for the first field.\n    $needs_or = FALSE;\n    if (!isset($field_base_table)) {\n      $needs_or = TRUE;\n      // Get the table name for the first field.\n      $field_table_name = key($this->fields[0]['storage']['details']['sql'][$this->age]);\n      $field_base_table = _field_sql_storage_tablealias($field_table_name, 0, $this);\n    }\n\n    if (isset($this->deleted)) {\n      $delete_condition = array(\n        'value' => (int) $this->deleted,\n        'operator' => '=',\n        'or' => $needs_or,\n      );\n      $this->addCondition($select_query, \"$field_base_table.deleted\", $delete_condition);\n    }\n\n    foreach ($this->entityConditions as $key => $condition) {\n      $condition['or'] = $needs_or;\n      $this->addCondition($select_query, \"$field_base_table.$key\", $condition);\n    }\n\n    // Order the query.\n    foreach ($this->order as $order) {\n      if ($order['type'] == 'entity') {\n        $key = $order['specifier'];\n        $select_query->orderBy(\"$field_base_table.$key\", $order['direction']);\n      }\n      elseif ($order['type'] == 'field') {\n        $specifier = $order['specifier'];\n        $field = $specifier['field'];\n        $table_alias = $table_aliases[$specifier['index']];\n        $sql_field = \"$table_alias.\" . _field_sql_storage_columnname($field['field_name'], $specifier['column']);\n        $select_query->orderBy($sql_field, $order['direction']);\n      }\n      elseif ($order['type'] == 'property') {\n        $select_query->orderBy(\"$base_table.\" . $order['specifier'], $order['direction']);\n      }\n    }\n\n    return array($select_query, $id_key);\n  }\n\n  /**\n   * Adds a join to the field table with the appropriate join type.\n   *\n   * @param SelectQuery $select_query\n   *   The select query to modify.\n   * @param string $field_name\n   *   The name of the field to join.\n   * @param string $table\n   *   The table against which to join.\n   * @param string $alias\n   *   The alias for the table. In most cases this should be the first letter\n   *   of the table, or the first letter of each \"word\" in the table.\n   * @param string $condition\n   *   The condition on which to join this table. If the join requires values,\n   *   this clause should use a named placeholder and the value or values to\n   *   insert should be passed in the 4th parameter. For the first table joined\n   *   on a query, this value is ignored as the first table is taken as the base\n   *   table. The token %alias can be used in this string to be replaced with\n   *   the actual alias. This is useful when $alias is modified by the database\n   *   system, for example, when joining the same table more than once.\n   * @param array $arguments\n   *   An array of arguments to replace into the $condition of this join.\n   *\n   * @return string\n   *   The unique alias that was assigned for this table.\n   */\n  protected function addFieldJoin(SelectQuery $select_query, $field_name, $table, $alias = NULL, $condition = NULL, $arguments = array()) {\n    // Find if we need a left or inner join by inspecting the field conditions.\n    $type = 'INNER';\n    foreach ($this->fieldConditions as $field_condition) {\n      if ($field_condition['field']['field_name'] == $field_name) {\n        $type = in_array($field_condition['operator'], static::$leftJoinOperators) ? 'LEFT' : 'INNER';\n        break;\n      }\n    }\n    return $select_query->addJoin($type, $table, $alias, $condition, $arguments);\n  }\n\n  /**\n   * Adds a condition to an already built SelectQuery (internal function).\n   *\n   * This is a helper for hook_entity_query() and hook_field_storage_query().\n   *\n   * @param SelectQuery $select_query\n   *   A SelectQuery object.\n   * @param string $sql_field\n   *   The name of the field.\n   * @param array $condition\n   *   A condition as described in EntityFieldQuery::fieldCondition() and\n   *   EntityFieldQuery::entityCondition().\n   * @param bool $having\n   *   HAVING or WHERE. This is necessary because SQL can't handle WHERE\n   *   conditions on aliased columns.\n   */\n  public function addCondition(SelectQuery $select_query, $sql_field, $condition, $having = FALSE) {\n    $needs_or = !empty($condition['or']) || in_array($condition['operator'], static::$leftJoinOperators);\n    if (\n      in_array($condition['operator'], array('CONTAINS', 'STARTS_WITH')) ||\n      !$needs_or\n    ) {\n      parent::addCondition($select_query, $sql_field, $condition, $having);\n      return;\n    }\n    $method = $having ? 'havingCondition' : 'condition';\n    $db_or = db_or()->condition($sql_field, $condition['value'], $condition['operator']);\n    if (strtoupper($condition['operator']) != 'IS NULL' && strtoupper($condition['operator']) != 'IS NOT NULL') {\n      $db_or->condition($sql_field, NULL, 'IS NULL');\n    }\n    $select_query->$method($db_or);\n  }\n\n  /**\n   * Checks if any of the conditions contains a LEFT JOIN operation.\n   *\n   * @param string $field_name\n   *   If provided only this field will be checked.\n   *\n   * @return bool\n   *   TRUE if any of the conditions contain a left join operator.\n   */\n  protected function containsLeftJoinOperator($field_name = NULL) {\n    foreach ($this->fieldConditions as $field_condition) {\n      if ($field_name && $field_condition['field']['field_name'] != $field_name) {\n        continue;\n      }\n      if (in_array($field_condition['operator'], static::$leftJoinOperators)) {\n        return TRUE;\n      }\n    }\n    return FALSE;\n  }\n\n}\n"
  },
  {
    "path": "src/Util/EntityFieldQueryRelationalConditionsInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\EntityFieldQueryRelationalConditions.\n */\n\nnamespace Drupal\\restful\\Util;\n\ninterface EntityFieldQueryRelationalConditionsInterface {\n\n  /**\n   * Get the relational filters.\n   *\n   * @return array[]\n   *   The relational filters.\n   */\n  public function getRelationships();\n\n  /**\n   * Add a relational filter.\n   *\n   * @param array $relational_filter\n   *   The filter to add.\n   */\n  public function addRelationship(array $relational_filter);\n\n}\n"
  },
  {
    "path": "src/Util/ExplorableDecoratorInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\ExplorableDecoratorInterface.\n */\n\nnamespace Drupal\\restful\\Util;\n\n/**\n * Class ExplorableDecorator.\n *\n * @package Drupal\\restful\\Util\n */\ninterface ExplorableDecoratorInterface {\n\n  /**\n   * Checks if the decorated object is an instance of something.\n   *\n   * @param string $class\n   *   Class or interface to check the instance.\n   *\n   * @return bool\n   *   TRUE if the decorated object is an instace of the $class. FALSE\n   *   otherwise.\n   */\n  public function isInstanceOf($class);\n\n}\n"
  },
  {
    "path": "src/Util/PersistableCache.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\PersistableCache.\n */\n\nnamespace Drupal\\restful\\Util;\n\nclass PersistableCache implements PersistableCacheInterface {\n\n  /**\n   * The data array.\n   *\n   * @var array\n   */\n  protected $data = array();\n\n  /**\n   * Tracks the loaded keys.\n   *\n   * @var string[]\n   */\n  protected $loaded = array();\n\n  /**\n   * The cache bin where to store the caches.\n   *\n   * @var string\n   */\n  protected $cacheBin = 'cache';\n\n  /**\n   * PersistableCache constructor.\n   *\n   * @param string $cache_bin\n   *   The cache bin where to store the persisted cache.\n   */\n  public function __construct($cache_bin = NULL) {\n    $this->cacheBin = $cache_bin ?: 'cache';\n  }\n\n\n  /**\n   * {@inheritdoc}\n   */\n  public function contains($key) {\n    return isset($this->data[$key]);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function &get($key) {\n    if (!$this->contains($key)) {\n      // Load from the real cache if it's not loaded yet.\n      $this->load($key);\n    }\n    if (!$this->contains($key)) {\n      $this->data[$key] = NULL;\n    }\n    return $this->data[$key];\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function set($key, $value) {\n    $this->data[$key] = $value;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function delete($key) {\n    unset($this->data[$key]);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function persist() {\n    foreach ($this->data as $key => $value) {\n      cache_set($key, $value, $this->cacheBin);\n    }\n  }\n\n  /**\n   * Persist the data in the cache backend during shutdown.\n   */\n  public function __destruct() {\n    $this->persist();\n  }\n\n  /**\n   * Checks if a key was already loaded before.\n   *\n   * @param string $key\n   *   The key to check.\n   *\n   * @return bool\n   *   TRUE if it was loaded before. FALSE otherwise.\n   */\n  protected function isLoaded($key) {\n    return isset($this->loaded[$key]);\n  }\n\n  /**\n   * Tries to load an item from the real cache.\n   *\n   * @param string $key\n   *   The key of the item.\n   */\n  protected function load($key) {\n    if ($this->isLoaded($key)) {\n      return;\n    }\n    // Mark the key as loaded.\n    $this->loaded[$key] = TRUE;\n    if ($cache = cache_get($key, $this->cacheBin)) {\n      $this->data[$key] = $cache->data;\n    }\n  }\n\n}\n"
  },
  {
    "path": "src/Util/PersistableCacheInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\PersistableCacheInterface.\n */\n\nnamespace Drupal\\restful\\Util;\n\ninterface PersistableCacheInterface {\n\n  /**\n   * Checks if the cache contains the key.\n   *\n   * @param string $key\n   *   The key to check.\n   *\n   * @return bool\n   *   TRUE if the key is present in the cache. FALSE otherwise.\n   */\n  public function contains($key);\n\n  /**\n   * Gets the memory reference of the cached item.\n   *\n   * @param string $key\n   *   The key to get.\n   *\n   * @return mixed\n   *   The reference to the value.\n   */\n  public function &get($key);\n\n  /**\n   * Gets the memory reference of the cached item.\n   *\n   * @param string $key\n   *   The key to set.\n   * @param mixed $value\n   *   The value to set.\n   */\n  public function set($key, $value);\n\n  /**\n   * Delete a cached item.\n   *\n   * @param string $key\n   *   The key to delete.\n   */\n  public function delete($key);\n\n  /**\n   * Persist the cache to the RESTful cache.\n   */\n  public function persist();\n\n}\n"
  },
  {
    "path": "src/Util/RelationalFilter.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\RelationalFilter.\n */\n\nnamespace Drupal\\restful\\Util;\n\n/**\n * Class RelationalFilter.\n *\n * @package Drupal\\restful\\Util\n */\nclass RelationalFilter implements RelationalFilterInterface {\n\n  /**\n   * Name of the field or property.\n   *\n   * @var string\n   */\n  protected $name;\n\n  /**\n   * Type of filter: field or property.\n   *\n   * @var string\n   */\n  protected $type;\n\n  /**\n   * The referenced entity type.\n   *\n   * @var string\n   */\n  protected $entityType;\n\n  /**\n   * The referenced bundles.\n   *\n   * @var string[]\n   */\n  protected $bundles = array();\n\n  /**\n   * Database column for field filters.\n   *\n   * @var string\n   */\n  protected $column;\n\n  /**\n   * Database column for the target table relationship.\n   *\n   * @var string\n   */\n  protected $targetColumn;\n\n  /**\n   * Constructs the RelationalFilter object.\n   *\n   * @param string $name\n   * @param string $type\n   * @param string $column\n   * @param string $entity_type\n   * @param array $bundles\n   * @param string $targetColumn\n   */\n  public function __construct($name, $type, $column, $entity_type, array $bundles = array(), $target_column = NULL) {\n    $this->name = $name;\n    $this->type = $type;\n    $this->column = $column;\n    $this->entityType = $entity_type;\n    $this->bundles = $bundles;\n    $this->targetColumn = $target_column;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getName() {\n    return $this->name;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getType() {\n    return $this->type;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getEntityType() {\n    return $this->entityType;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getBundles() {\n    return $this->bundles;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getColumn() {\n    return $this->column;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function getTargetColumn() {\n    return $this->targetColumn;\n  }\n\n}\n"
  },
  {
    "path": "src/Util/RelationalFilterInterface.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\RelationalFilterInterface.\n */\n\nnamespace Drupal\\restful\\Util;\n\n/**\n * Interface RelationalFilterInterface.\n *\n * @package Drupal\\restful\\Util\n */\ninterface RelationalFilterInterface {\n\n  const TYPE_FIELD = 'field';\n  const TYPE_PROPERTY = 'property';\n\n  /**\n   * Get the name.\n   *\n   * @return string\n   *   The name.\n   */\n  public function getName();\n\n  /**\n   * Get the type.\n   *\n   * @return string\n   *   The type.\n   */\n  public function getType();\n\n  /**\n   * Gets the entity type.\n   *\n   * @return string\n   *   The type.\n   */\n  public function getEntityType();\n\n  /**\n   * The bundles.\n   *\n   * @return string[]\n   *   Array of bundles.\n   */\n  public function getBundles();\n\n  /**\n   * Database column for field filters.\n   *\n   * @return string\n   *   The DB column.\n   */\n  public function getColumn();\n\n  /**\n   * Database column for the target table relationship.\n   *\n   * @return string\n   *   The DB column.\n   */\n  public function getTargetColumn();\n\n}\n"
  },
  {
    "path": "src/Util/StringHelper.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful\\Util\\String.\n */\n\nnamespace Drupal\\restful\\Util;\n\n/**\n * Class StringHelper.\n *\n * @package Drupal\\restful\\Util\n */\nclass StringHelper {\n\n  /**\n   * Turns a string into camel case.\n   *\n   * @param string $input\n   *   The input string.\n   *\n   * @return string\n   *   The camelized string.\n   */\n  public static function camelize($input) {\n    $input = preg_replace('/[-_]/', ' ', $input);\n    $input = ucwords($input);\n    $parts = explode(' ', $input);\n    return implode('', $parts);\n  }\n\n  /**\n   * Remove the string prefix from the token value.\n   *\n   * @param string $prefix\n   *   The prefix to remove.\n   * @param string $haystack\n   *   The string to remove the prefix from.\n   *\n   * @return string\n   *   The prefixless string. NULL if the prefix is not found.\n   */\n  public static function removePrefix($prefix, $haystack) {\n    $position = strpos($haystack, $prefix);\n    if ($position === FALSE) {\n      return NULL;\n    }\n    return substr($haystack, $position + strlen($prefix));\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulAuthenticationTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulAuthenticationTestCase.\n */\n\nuse Drupal\\restful\\Plugin\\AuthenticationPluginManager;\nuse Drupal\\Component\\Plugin\\PluginManagerInterface;\nuse Drupal\\restful\\Http\\Request;\n\n/**\n * Class RestfulAuthenticationTestCase.\n */\nclass RestfulAuthenticationTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * Holds the generated account.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * Holds the current value of the $_SERVER super global.\n   *\n   * @var array\n   */\n  protected $originalServer;\n\n  /**\n   * Holds the current value of the $_SESSION super global.\n   *\n   * @var array\n   */\n  protected $originalSession;\n\n  /**\n   * The plugin manager.\n   *\n   * @var PluginManagerInterface\n   */\n  protected $pluginManager;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Authentication',\n      'description' => 'Test the request authentication.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n    // Create a custom user that we'll use to identify.\n    $this->account = $this->drupalCreateUser();\n\n    $this->originalServer = $_SERVER;\n    $this->originalSessions = $_SESSION;\n    $this->pluginManager = AuthenticationPluginManager::create();\n  }\n\n  public function tearDown() {\n    // Put back the $_SERVER array.\n    $_SERVER = $this->originalServer;\n    $_SESSION = $this->originalSession;\n    parent::tearDown();\n  }\n\n  /**\n   * Test authenticating a user.\n   */\n  function testAuthentication() {\n    // Start a session just in case we're executing the code from CLI.\n    drupal_session_start();\n    global $user;\n    $resource_manager = restful()->getResourceManager();\n    $request = Request::create('');\n    $handler = $resource_manager->getPlugin('main:1.5');\n\n    // Case 1. Check that the handler has the expected authentication providers.\n    $providers = array_keys($this->pluginManager->getDefinitions());\n    $plugin_definition = $handler->getPluginDefinition();\n    foreach ($plugin_definition['authenticationTypes'] as $provider_name) {\n      $this->assertTrue(in_array($provider_name, $providers), format_string('The %name authorization type was found.', array(\n        '%name' => $provider_name,\n      )));\n    }\n\n    // Case 2. Test that the account from the authentication manager is the\n    // logged in user.\n\n    // We need to hijack the global user object in order to force it to be our\n    // test account and make the cookie authentication provider to resolve it.\n    $user = $this->account;\n    $handler->setRequest($request);\n    $handler->setAccount(NULL);\n    $this->assertEqual($this->account->uid, $handler->getAccount(FALSE)->uid, 'The authentication manager resolved the currently logged in user.');\n\n    $cookie_provider = $this->pluginManager->createInstance('cookie');\n\n    // Case 3. Test the 'cookie_auth' authentication provider.\n    $this->assertEqual($this->account->uid, $cookie_provider->authenticate($request)->uid, 'The cookie provider resolved the currently logged in user.');\n\n    $user = drupal_anonymous_user();\n    // Case 4. Test that the 'cookie_auth' resolves the anonymous user.\n    $this->assertEqual(0, $cookie_provider->authenticate($request)->uid, 'The cookie provider resolved the anonymous user.');\n\n    $basic_auth_provider = $this->pluginManager->createInstance('basic_auth');\n\n    // Case 5. Valid login using basic auth.\n    $_SERVER['PHP_AUTH_USER'] = $this->account->name;\n    $_SERVER['PHP_AUTH_PW'] = $this->account->pass_raw;\n    $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = NULL;\n    $this->assertEqual($this->account->uid, $basic_auth_provider->authenticate($request)->uid, 'The basic auth provider resolved the currently logged in user.');\n\n    // Case 6. Valid login using REDIRECT_HTTP_AUTHORIZATION.\n    $_SERVER['PHP_AUTH_USER'] = NULL;\n    $_SERVER['PHP_AUTH_PW'] = NULL;\n    $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = 'Basic ' . base64_encode($this->account->name . ':' . $this->account->pass_raw);\n    $this->assertEqual($this->account->uid, $basic_auth_provider->authenticate($request)->uid, 'The basic auth provider resolved the currently logged in user. Using REDIRECT_HTTP_AUTHORIZATION.');\n\n    // Case 7. Invalid pass for basic auth.\n    $_SERVER['PHP_AUTH_USER'] = $this->account->name;\n    $_SERVER['PHP_AUTH_PW'] = $this->randomName();\n    $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = NULL;\n    $this->assertNull($basic_auth_provider->authenticate($request), 'The basic auth provider could not resolve a user with invalid password.');\n\n    // Case 8. Invalid username for basic auth.\n    $_SERVER['PHP_AUTH_USER'] = $this->randomName();\n    $_SERVER['PHP_AUTH_PW'] = $this->account->pass_raw;\n    $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = NULL;\n    $this->assertNull($basic_auth_provider->authenticate($request), 'The basic auth provider could not resolve a user with invalid username.');\n\n    // Case 9. Valid login using REDIRECT_HTTP_AUTHORIZATION.\n    $_SERVER['PHP_AUTH_USER'] = NULL;\n    $_SERVER['PHP_AUTH_PW'] = NULL;\n    $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = 'Basic ' . base64_encode($this->randomName() . ':' . $this->randomName());\n    $this->assertNull($basic_auth_provider->authenticate($request), 'The basic auth provider could not resolve a user with invalid encoded username & password. Using REDIRECT_HTTP_AUTHORIZATION.');\n\n    // Case 11. Accessing a resource with optional authentication.\n\n    // We are getting a 403 instead of 401, as the access is now based on the\n    // permissions.\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles' => FALSE));\n    $handler = $resource_manager->getPlugin('users:1.0');\n    $handler->setRequest(Request::create('api/v1.0/users'));\n    $handler->setPath('');\n    $handler->setAccount(NULL);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['self'], url('api/v1.0/users/0', array('absolute' => TRUE)));\n    $this->assertEqual(count($result), 1, 'The anonymous users can only see themselves.');\n\n    // To assert permissions control access to the resource, we change the\n    // permission for anonymous to access other user's profile.\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles' => TRUE));\n    // If the process function does not throw an exception, the test passes.\n    restful()->getFormatterManager()->format($handler->process(), 'json');\n  }\n\n\n  /**\n   * Test recording of access time.\n   */\n  public function testAccessTime() {\n    global $user;\n\n    $user1 = $this->drupalCreateUser();\n    $user2 = $this->drupalCreateUser();\n\n    $handler = restful()->getResourceManager()->getPlugin('main:1.5');\n\n    // Case 1. Ensure that access time is recorded for cookie auth.\n    $user = $user1;\n\n    $user1_access_time_before = db_query('SELECT access FROM {users} WHERE uid = :d', array(':d' => $user1->uid))->fetchObject();\n\n    // Perform request authentication.\n    $handler->getAccount();\n\n    $user1_access_time = db_query('SELECT access FROM {users} WHERE uid = :d', array(':d' => $user1->uid))->fetchObject();\n    $this->assertEqual($user1_access_time->access, REQUEST_TIME, 'Cookie authenticated user access time is updated.');\n\n    $this->assertNotEqual($user1_access_time_before->access, $user1_access_time->access, 'Access time before and after request are equal.');\n\n    // Case 2. Ensure that access time is recorded for basic auth.\n    $user = $user2;\n\n    $_SERVER['PHP_AUTH_USER'] = $user2->name;\n    $_SERVER['PHP_AUTH_PW'] = $user2->pass_raw;\n    $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = NULL;\n    $handler = restful()->getResourceManager()->getPlugin('articles:1.0');\n\n    // Perform request authentication.\n    $handler->getAccount();\n\n    $user2_access_time = db_query('SELECT access FROM {users} WHERE uid = :d', array(':d' => $user2->uid))->fetchObject();\n    $this->assertEqual($user2_access_time->access, REQUEST_TIME, 'Basic authenticated user access time is updated.');\n\n    // Case 3. Ensure that the timestamp gets updated.\n    $user = $user1;\n\n    // Get a timestamp that is in the past.\n    $the_past = REQUEST_TIME - variable_get('session_write_interval');\n\n    // To begin, we'll set the timestamp for user1 back a little bit.\n    db_update('users')\n      ->fields(array('access' => $the_past))\n      ->condition('uid', $user1->uid)\n      ->execute();\n\n    $user1_pre_access_time = db_query('SELECT access FROM {users} WHERE uid = :d', array(':d' => $user1->uid))->fetchObject();\n    $this->assertEqual($user1_pre_access_time->access, $the_past, 'Set user1 access time to a time in the past.');\n\n    // Perform an authenticated request.\n    $this->drupalGet('/api/v1.5/main', array(), array(\n        'Authorization' => 'Basic ' . base64_encode($user1->name . ':' . $user1->pass_raw))\n    );\n\n    $user1_post_access_time = db_query('SELECT access FROM {users} WHERE uid = :d', array(':d' => $user1->uid))->fetchObject();\n\n    $this->assertEqual($user1_post_access_time->access, REQUEST_TIME, 'Basic authenticated user access time is updated.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulAutoCompleteTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulAutoCompleteTestCase\n */\n\nclass RestfulAutoCompleteTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Autocomplete',\n      'description' => 'Test the autocomplete functionality.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * @var \\stdClass.\n   *\n   * The user object.\n   */\n  protected $user;\n\n  function setUp() {\n    parent::setUp('restful_test');\n\n    $this->user = $this->drupalCreateUser();\n  }\n\n  /**\n   * Test the autocomplete functionality.\n   */\n  function testAutocomplete() {\n    // Create terms.\n    restful_test_create_vocabulary_and_terms('tags', FALSE);\n\n    $handler = restful_get_restful_handler('test_tags');\n\n    // \"CONTAINS\" operator.\n    $request = array(\n      'autocomplete' => array(\n        'string' => 'ter',\n      ),\n    );\n    $result = $handler->get('', $request);\n\n    $expected_result = array (\n      1 => 'term1',\n      2 => 'term2',\n      3 => 'term3',\n    );\n    $this->assertEqual($result, $expected_result, 'Autocomplete with \"CONTAINS\" operator returned expected results.');\n\n    // \"STARTS_WITH\" operator.\n    $request = array(\n      'autocomplete' => array(\n        'string' => 'term1',\n        'operator' => 'STARTS_WITH'\n      ),\n    );\n    $result = $handler->get('', $request);\n\n    $expected_result = array (\n      1 => 'term1',\n    );\n    $this->assertEqual($result, $expected_result, 'Autocomplete with \"CONTAINS\" operator returned expected results.');\n\n    // Empty query.\n    $request = array(\n      'autocomplete' => array(\n        'string' => 'non-existing',\n      ),\n    );\n    $result = $handler->get('', $request);\n    $this->assertFalse($result, 'No values returned from empty query.');\n\n    // Test autocomplete for users.\n    $handler = restful_get_restful_handler('users');\n    $request = array(\n      'autocomplete' => array(\n        'string' => substr($this->user->name, 0, 3),\n      ),\n    );\n    $result = $handler->get('', $request);\n    $this->assertTrue($result, 'Results has returned for entity without a bundle key.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulCommentTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulCommentTestCase\n */\n\nclass RestfulCommentTestCase extends DrupalWebTestCase {\n\n  /**\n   * Holds the user account that owns the content.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * Article content.\n   *\n   * @var object\n   */\n  protected $node;\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Comment integration',\n      'description' => 'Test the CRUD of a comment.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example', 'comment');\n    $this->account = $this->drupalCreateUser(array(\n      'create article content',\n      'edit own comments',\n    ));\n\n    $settings = array(\n      'type' => 'article',\n      'title' => $this->randomName(),\n      'uid' => $this->account->uid,\n    );\n    $this->node = $this->drupalCreateNode($settings);\n\n    // Add a comment_text field instead of comment_body field as the\n    // comment_body property is required, see entity_metadata_comment_entity_property_info()\n    // for more information.\n    $this->addTextField('comment', 'comment_node_article', 'comment_text');\n  }\n\n  /**\n   * Test creating a comment (POST method).\n   */\n  public function testCreateComment() {\n    $resource_manager = restful()->getResourceManager();\n    $this->drupalLogin($this->account);\n\n    $handler = $resource_manager->getPlugin('comments:1.0');\n\n    // @todo Remove \"administer comments\" when https://www.drupal.org/node/2236229 is fixed.\n    $permissions = array(\n      'post comments',\n      'administer comments',\n    );\n    // Set a different user from the logged in user, to assert the comment's\n    // author is set correctly.\n    $user = $this->drupalCreateUser($permissions);\n    $handler->setAccount($user);\n\n    $label = $this->randomName();\n    $request = array(\n      'label' => $label,\n      'nid' => $this->node->nid,\n    );\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPost($request), 'json'));\n    $result = $result['data'];\n\n    $comment = comment_load($result[0]['id']);\n    $this->assertEqual($comment->uid, $user->uid, 'Correct user was set to be the author of the comment.');\n    $this->assertEqual($comment->nid, $this->node->nid, 'Correct nid set.');\n    $this->assertEqual($comment->subject, $label, 'Correct subject set.');\n  }\n\n  /**\n   * Test creating a comment (GET method).\n   */\n  public function testRetrieve() {\n    $resource_manager = restful()->getResourceManager();\n\n    $label = $this->randomName();\n    $settings = array(\n      'node_type' => 'comment_node_article',\n      'nid' => $this->node->nid,\n      'uid' => $this->account->uid,\n      'subject' => $label,\n    );\n    $comment = $this->createComment($settings);\n    $id = $comment->cid;\n\n    $handler = $resource_manager->getPlugin('comments:1.0');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doGet($id), 'json'));\n    $result = $result['data'];\n\n    $comment = $result[0];\n    $this->assertEqual($comment['nid'], $this->node->nid, 'Correct nid get.');\n    $this->assertEqual($comment['label'], $label, 'Correct subject get.');\n  }\n\n  /**\n   * Test updating a comment (PUT method).\n   */\n  public function testUpdateCommentAsPut() {\n    $resource_manager = restful()->getResourceManager();\n\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n    $text = $this->randomName();\n\n    $settings = array(\n      'node_type' => 'comment_node_article',\n      'nid' => $this->node->nid,\n      'uid' => $this->account->uid,\n      'subject' => $label,\n    );\n    $settings['comment_text'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $comment = $this->createComment($settings);\n    $id = $comment->cid;\n\n    $handler = $resource_manager->getPlugin('comments:1.0');\n    $handler->setAccount($this->account);\n    $request = array('label' => $new_label);\n\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPut($id, $request), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $id,\n        'label' => $new_label,\n        'self' => $handler->versionedUrl($id),\n        'nid' => $this->node->nid,\n        'comment_text' => NULL,\n      ),\n    );\n\n    $result[0]['comment_text'] = trim(strip_tags($result[0]['comment_text']));\n    $this->assertEqual($result, $expected_result);\n  }\n\n  /**\n   * Test updating a comment (PATCH method).\n   */\n  public function testUpdateCommentAsPatch() {\n    $resource_manager = restful()->getResourceManager();\n\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n    $text = $this->randomName();\n\n    $settings = array(\n      'node_type' => 'comment_node_article',\n      'nid' => $this->node->nid,\n      'uid' => $this->account->uid,\n      'subject' => $label,\n    );\n    $settings['comment_text'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $comment = $this->createComment($settings);\n    $id = $comment->cid;\n\n    $handler = $resource_manager->getPlugin('comments:1.0');\n    $handler->setAccount($this->account);\n    $request = array('label' => $new_label);\n\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPatch($id, $request), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $id,\n        'label' => $new_label,\n        'self' => $handler->versionedUrl($id),\n        'nid' => $this->node->nid,\n        'comment_text' => $text,\n      ),\n    );\n\n    $result[0]['comment_text'] = trim(strip_tags($result[0]['comment_text']));\n    $this->assertEqual($result, $expected_result);\n  }\n\n  /**\n   * Test deleting a comment (DELETE method).\n   */\n  public function testDeleteComment() {\n    $resource_manager = restful()->getResourceManager();\n\n    $label = $this->randomName();\n    $text = $this->randomName();\n\n    $settings = array(\n      'node_type' => 'comment_node_article',\n      'nid' => $this->node->nid,\n      'uid' => $this->account->uid,\n      'subject' => $label,\n    );\n    $settings['comment_text'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $comment = $this->createComment($settings);\n    $id = $comment->cid;\n\n    $handler = $resource_manager->getPlugin('comments:1.0');\n    // Set a different user from the comment user, as only the administer\n    // can delete comments.\n    $user = $this->drupalCreateUser(array('administer comments'));\n    $handler->setAccount($user);\n    $handler->doDelete($id);\n\n    $result = !comment_load($id);\n    $this->assertTrue($result, 'Comment deleted.');\n  }\n\n  /**\n   * Adds a text field.\n   *\n   * @param string $entity_type\n   *   The entity type.\n   * @param string $bundle.\n   *   The bundle name.\n   * @param string $field_name.\n   *   The field name.\n   */\n  protected function addTextField($entity_type, $bundle, $field_name) {\n    // Text - single, with text processing.\n    $field = array(\n      'field_name' => $field_name,\n      'type' => 'text_long',\n      'entity_types' => array($entity_type),\n      'cardinality' => 1,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'field_name' => $field_name,\n      'bundle' => $bundle,\n      'entity_type' => $entity_type,\n      'label' => t('Text single with text processing'),\n      'settings' => array(\n        'text_processing' => 1,\n      ),\n    );\n    field_create_instance($instance);\n  }\n\n  /**\n   * Creates a comment based on default settings.\n   *\n   * @param array $settings\n   *   An associative array of settings to change from the defaults, keys are\n   *   comment properties, for example 'subject' => 'Hello, world!'.\n   * @return object\n   *   Created comment object.\n   */\n  protected function createComment($settings = array()) {\n    // Populate defaults array.\n    $settings += array(\n      'cid'          => FALSE,\n      'pid'          => 0,\n      'subject'      => $this->randomName(8),\n      'status'       => COMMENT_PUBLISHED,\n      'node_type'    => 'comment_node_article',\n      'language'     => LANGUAGE_NONE,\n      'comment_text' => array(LANGUAGE_NONE => array(array())),\n    );\n\n    // If the comment's user uid is not specified manually, use the currently\n    // logged in user if available, or else the user running the test.\n    if (!isset($settings['uid'])) {\n      if ($this->loggedInUser) {\n        $settings['uid'] = $this->loggedInUser->uid;\n      }\n      else {\n        global $user;\n        $settings['uid'] = $user->uid;\n      }\n    }\n\n    // Merge comment text field value and format separately.\n    $body = array(\n      'value' => $this->randomName(32),\n      'format' => filter_default_format(),\n    );\n    $settings['comment_text'][$settings['language']][0] += $body;\n\n    $comment = (object) $settings;\n    comment_save($comment);\n\n    return $comment;\n  }\n}\n"
  },
  {
    "path": "tests/RestfulCreateEntityTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulCreateEntityTestCase\n */\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\n/**\n * Class RestfulCreateEntityTestCase.\n */\nclass RestfulCreateEntityTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Create entity',\n      'description' => 'Test the creation of an entity.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * @var string\n   *\n   * Holds the path to a random generated image for upload purposes.\n   */\n  private $imagePath;\n\n  /**\n   * @var \\stdClass\n   *\n   * Holds the created account.\n   */\n  protected $account;\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test', 'entityreference');\n\n    // Add common fields, vocabulary and terms.\n    restful_test_add_fields();\n\n    $images = $this->drupalGetTestFiles('image');\n    $image = reset($images);\n    $this->imagePath = drupal_realpath($image->uri);\n    $this->account = $this->drupalCreateUser();\n  }\n\n  /**\n   * Test creating an entity (POST method).\n   */\n  public function testCreateEntity() {\n    $resource_manager = restful()->getResourceManager();\n    // Create test entities to be referenced.\n    $ids = array();\n    for ($i = 0; $i < 2; $i++) {\n      /* @var \\Entity $entity */\n      $entity = entity_create('entity_test', array('name' => 'main'));\n      $entity->save();\n      $ids[] = $entity->pid;\n    }\n\n    $images = array();\n    foreach ($this->drupalGetTestFiles('image') as $file) {\n      $file = file_save($file);\n      $images[] = $file->fid;\n    }\n\n    $resource_manager->clearPluginCache('main:1.1');\n    $handler = $resource_manager->getPlugin('main:1.1');\n\n    $query = new EntityFieldQuery();\n    $result = $query\n      ->entityCondition('entity_type', 'taxonomy_term')\n      ->entityCondition('bundle', 'test_vocab')\n      ->execute();\n\n    $tids = array_keys($result['taxonomy_term']);\n\n    $text1 = $this->randomName();\n    $text2 = $this->randomName();\n    $request = array(\n      'text_single' => $text1,\n      'text_multiple' => array($text1, $text2),\n      'text_single_processing' => $text1,\n      'text_multiple_processing' => array($text1, $text2),\n      'entity_reference_single' => $ids[0],\n      'entity_reference_multiple' => $ids,\n      'term_single' => $tids[0],\n      'term_multiple' => array($tids[0], $tids[1]),\n      'file_single' => $images[0],\n      'file_multiple' => array($images[0], $images[1]),\n      'image_single' => $images[0],\n      'image_multiple' => array($images[0], $images[1]),\n    );\n\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPost($request)));\n    $response = $response['data'];\n    $result = $response[0];\n\n    $text_single = trim(strip_tags($result['text_single']));\n    $text_multiple = array(\n      trim(strip_tags($result['text_multiple'][0])),\n      trim(strip_tags($result['text_multiple'][1])),\n    );\n\n    $expected_result = $request;\n\n    // Strip some elements, and the text, for easier assertion.\n    $striped_result = $result;\n    unset($striped_result['id']);\n    unset($striped_result['label']);\n    unset($striped_result['self']);\n    unset($striped_result['entity_reference_single_resource']);\n    unset($striped_result['entity_reference_multiple_resource']);\n\n    $striped_result['text_single'] = $text_single;\n    $striped_result['text_multiple'] = $text_multiple;\n\n    $striped_result['text_single_processing'] = $text_single;\n    $striped_result['text_multiple_processing'] = $text_multiple;\n\n    ksort($striped_result);\n    ksort($expected_result);\n    $this->assertEqual($expected_result, $striped_result, 'Entity was created with correct values.');\n\n    $this->assertEqual($result['entity_reference_single_resource']['id'], $ids[0], ' Entity reference single resource was created correctly');\n    $this->assertEqual($result['entity_reference_multiple_resource'][0]['id'], $ids[0], ' Entity reference multiple resource was created correctly');\n\n    // Create an entity with empty request.\n    try {\n      $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST));\n      $handler->setPath('');\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('User can create an entity with empty request.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('User cannot create an entity with empty request.');\n    }\n\n    // Create an entity with invalid property name.\n    $request['invalid'] = 'wrong';\n    try {\n      $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n      $handler->setPath('');\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('User can create an entity with invalid property name.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('User cannot create an entity with invalid property name.');\n    }\n\n    // Create entity with comma separated multiple entity reference.\n    $request = array('entity_reference_multiple' => implode(',', $ids));\n    $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n    $handler->setPath('');\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertEqual($result['entity_reference_multiple'], $ids, 'Created entity with comma separated multiple entity reference.');\n\n    // Create entity with comma separated multiple taxonomy term reference.\n    $ids = array($tids[0], $tids[1]);\n    $request = array('term_multiple' => implode(',', $ids));\n    $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n    $handler->setPath('');\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertEqual($result['term_multiple'], $ids, 'Created entity with comma separated multiple taxonomy term reference.');\n\n    // Create entity with comma separated multiple file reference.\n    $ids = array($images[0], $images[1]);\n    $request = array('file_multiple' => implode(',', $ids));\n    $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n    $handler->setPath('');\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertEqual($result['file_multiple'], $ids, 'Created entity with comma separated multiple file reference.');\n\n    // Create entity with comma separated multiple image reference.\n    $ids = array($images[0], $images[1]);\n    $request = array('image_multiple' => implode(',', $ids));\n    $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n    $handler->setPath('');\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertEqual($result['image_multiple'], $ids, 'Created entity with comma separated multiple image reference.');\n\n  }\n\n  /**\n   * Test access for file upload.\n   */\n  public function testFileUploadAccess() {\n    variable_set('restful_file_upload', TRUE);\n    variable_set('restful_file_upload_allow_anonymous_user', TRUE);\n    // Make sure the user is logged out even when using the UI tests.\n    $this->drupalLogout();\n\n    // Test access for anonymous user (allowed).\n    $handler = $this->fileResource();\n    $this->assertTrue($handler->access(), 'File upload is allowed to anonymous users.');\n    variable_set('restful_file_upload_allow_anonymous_user', FALSE);\n    // Now that we have a successfully uploaded file, make sure it's the same\n    // file that was uploaded.\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process()));\n    $original = hash_file('md5', $this->imagePath);\n    $file = file_load($response['data'][0][0]['id']);\n    $uploaded = hash_file('md5', file_create_url($file->uri));\n    $this->assertEqual($original, $uploaded, 'Original and uploaded file are identical.');\n    // Test access for anonymous user (denied).\n    $handler = $this->fileResource();\n    $this->assertFalse($handler->access(), 'File upload is denied to anonymous users.');\n\n    $this->drupalLogin($this->account);\n    // Test access for authenticated users (allowed).\n    $handler = $this->fileResource();\n    $this->assertTrue($handler->access(), 'File upload is allowed to authenticated users.');\n    // Test access for authenticated users (denied).\n    variable_set('restful_file_upload', FALSE);\n    try {\n      $this->fileResource();\n      $this->fail('The file upload endpoint is not disalbed.');\n    }\n    catch (\\Drupal\\restful\\Exception\\ServiceUnavailableException $e) {\n      $this->pass('The file upload endpoint is disalbed.');\n    }\n  }\n\n  /**\n   * Uploads a file issuing a POST HTTP request.\n   *\n   * @return \\Drupal\\restful\\Plugin\\resource\\ResourceInterface\n   *   The file resource.\n   *\n   * @throws \\Drupal\\restful\\Exception\\BadRequestException\n   * @throws \\Drupal\\restful\\Exception\\ServiceUnavailableException\n   */\n  protected function fileResource() {\n    // We are setting the $_FILES array directly on tests, so we need to\n    // override the is_uploaded_file PHP method by setting a custom variable.\n    // Otherwise the manually set file will not be detected.\n    variable_set('restful_insecure_uploaded_flag', TRUE);\n\n    // Clear the plugin definition cache to regenerate authenticationOptional\n    // based on the variable value.\n    $resource_manager = restful()->getResourceManager();\n    $resource_manager->clearPluginCache('files_upload_test:1.0');\n    if (!$handler = $resource_manager->getPlugin('files_upload_test:1.0')) {\n      throw new \\Drupal\\restful\\Exception\\ServiceUnavailableException();\n    }\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['authenticationOptional'] = variable_get('restful_file_upload_allow_anonymous_user', FALSE);\n    $handler->setPluginDefinition($plugin_definition);\n    $account = $this->account;\n    if (!$this->loggedInUser) {\n      $account = drupal_anonymous_user();\n    }\n    $handler->setAccount($account);\n    // Due to entity_metadata_file_access we need to set the global user to the\n    // user for the test.\n    $GLOBALS['user'] = $account;\n\n    $value = '@' . $this->imagePath;\n\n    // PHP 5.5 introduced a CurlFile object that deprecates the old @filename\n    // syntax. See: https://wiki.php.net/rfc/curl-file-upload\n    if (function_exists('curl_file_create')) {\n      $value = curl_file_create($this->imagePath);\n    }\n\n    $tmp_name = drupal_tempnam('/tmp', 'restful_test_');\n    file_put_contents($tmp_name, file_get_contents($this->imagePath));\n    $headers = new \\Drupal\\restful\\Http\\HttpHeaderBag(array('Content-Type' => 'multipart/form-data'));\n    // Mock the $_FILES global variable.\n    $files = array(\n      'my-filename' => array(\n        'error' => 0,\n        'name' => basename($this->imagePath),\n        'size' => filesize($this->imagePath),\n        'tmp_name' => $tmp_name,\n        'type' => 'image/png',\n      ),\n    );\n    $handler->setRequest(Request::create('api/file-upload', array(), RequestInterface::METHOD_POST, $headers, FALSE, NULL, array(), $files, array(), array('filename' => $value)));\n    $handler->setPath('');\n    return $handler;\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulCreateNodeTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulCreateNodeTestCase\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulCreateNodeTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Node integration',\n      'description' => 'Test the creation of a node entity type.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example');\n  }\n\n  /**\n   * Test creating a node (POST method).\n   */\n  public function testCreateNode() {\n    $resource_manager = restful()->getResourceManager();\n    $user1 = $this->drupalCreateUser();\n    $this->drupalLogin($user1);\n\n    $handler = $resource_manager->getPlugin('articles:1.1');\n\n    // Set a different user from the logged in user, to assert the node's author\n    // is set correctly.\n    $user2 = $this->drupalCreateUser(array('create article content'));\n    $handler->setAccount($user2);\n\n    $text1 = $this->randomName();\n    $request = array('label' => $text1);\n    $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n\n    $node = node_load($result[0]['id']);\n    $this->assertEqual($node->uid, $user2->uid, 'Correct user was set to be the author of the node.');\n    $this->assertEqual($node->title, $text1, 'Correct title set.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulCreatePrivateNodeTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulCreatePrivateNodeTestCase\n */\n\nclass RestfulCreatePrivateNodeTestCase extends DrupalWebTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Node access integration',\n      'description' => 'Test the creation of a node entity type with private access.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_node_access_test');\n    // Add entity reference fields.\n    restful_test_add_fields('node', 'article');\n\n    // Rebuild node access.\n    node_access_rebuild();\n  }\n\n  /**\n   * Test creating a node (POST method) with reference to existing private node.\n   *\n   * In this test we make sure that entity_metadata_no_hook_node_access()\n   * returns TRUE, thus allows access to set the entity reference property.\n   *\n   * @see restful_node_access_test_node_access_records()\n   */\n  public function testCreateNodeWithReference() {\n    $user1 = $this->drupalCreateUser(array('create article content'));\n    $user2 = $this->drupalCreateUser(array('create article content'));\n    $this->drupalLogin($user1);\n\n    $settings = array(\n      'type' => 'article',\n      'uid' => $user1->uid,\n    );\n\n    // Create a node that will be set to private.\n    $node1 = $this->drupalCreateNode($settings);\n\n    // Assert user has access to the node.\n    $this->assertTrue(node_access('view', $node1, $user1), 'Author has access to view node.');\n\n    // Assert another user doesn't have access to the node.\n    $this->assertFalse(node_access('view', $node1, $user2), 'Authenticated user, but not author does not have access to view the node.');\n\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.2');\n    $formatter = restful()->getFormatterManager()->getPlugin('json');\n    $formatter->setResource($handler);\n    $handler->setAccount($user1);\n\n    $parsed_body = array(\n      'label' => $this->randomName(),\n      'entity_reference_single' => $node1->nid,\n    );\n    $result = $formatter->prepare($handler->doPost($parsed_body));\n\n    $this->assertTrue($result, 'Private node with reference to another private node was created.');\n\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulCreateTaxonomyTermTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulCreateTaxonomyTermTestCase\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulCreateTaxonomyTermTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Taxonomy term integration',\n      'description' => 'Test the creation of a taxonomy term entity type.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test the creation of a taxonomy term entity type.\n   */\n  public function testCreate() {\n    $resource_manager = restful()->getResourceManager();\n    $user1 = $this->drupalCreateUser(array('create article content'));\n    $this->drupalLogin($user1);\n\n    $handler = $resource_manager->getPlugin('test_tags:1.0');\n    $handler->setAccount($user1);\n\n    $text1 = $this->randomName();\n    $request = array('label' => $text1);\n\n    $handler->setRequest(Request::create('', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $request));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n\n    $id = $result[0]['id'];\n    $this->assertTrue($id, 'Term was created by a non-admin user.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulCsrfTokenTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulCsrfTokenTestCase\n */\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulCsrfTokenTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * Write operations.\n   *\n   * @var string[]\n   */\n  protected $writeOperations = array(\n    RequestInterface::METHOD_POST,\n    RequestInterface::METHOD_PUT,\n    RequestInterface::METHOD_PATCH,\n    RequestInterface::METHOD_DELETE,\n  );\n\n  /**\n   * Holds the current value of the $_SERVER super global.\n   *\n   * @var array\n   */\n  protected $originalServer;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'CSRF token',\n      'description' => 'Test the validation of a CSRF token for write operations.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_example');\n  }\n\n  /**\n   * Test the validation of a CSRF token for authenticated users.\n   */\n  public function testCsrfToken() {\n    global $user;\n\n    $permissions = array(\n      'create article content',\n      'edit any article content',\n      'delete any article content',\n    );\n    $account = $this->drupalCreateUser($permissions);\n    $this->drupalLogin($account);\n    $user = $account;\n\n    // Check CSRF is not checked for read operations.\n    $this->checkCsrfRequest(array(RequestInterface::METHOD_GET), FALSE);\n\n    $this->checkCsrfRequest($this->writeOperations, TRUE);\n  }\n\n  /**\n   * Test the validation of a CSRF token for anonymous users.\n   */\n  public function testCsrfTokenAnon() {\n    global $user;\n    $user = drupal_anonymous_user();\n\n    // Allow anonymous user to CRUD article content.\n    $permissions = array(\n      'create article content' => TRUE,\n      'edit any article content' => TRUE,\n      'delete any article content' => TRUE,\n    );\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, $permissions);\n\n    $this->checkCsrfRequest($this->writeOperations, FALSE, FALSE);\n  }\n\n  /**\n   * Perform requests without, with invalid and with valid CSRF tokens.\n   *\n   * @param array $methods\n   *   Array with HTTP method names.\n   * @param bool $csrf_required\n   *   Indicate if CSRF is required for the request, thus errors would be set if\n   *   no CSRF or invalid one is sent with the request.\n   * @param bool $auth_user\n   *   Determine if a user should be created and logged in. Defaults to TRUE.\n   */\n  protected function checkCsrfRequest($methods = array(), $csrf_required, $auth_user = TRUE) {\n    $params['@role'] = $auth_user ? 'authenticated' : 'anonymous';\n\n    foreach ($methods as $method) {\n      $request = Request::isReadMethod($method) ? array() : array('label' => $this->randomName());\n      $params['@method'] = $method;\n\n      // No CSRF token.\n      $result = $this->httpRequest($this->getPath($method), $method, $request, array(\n        'Content-Type' => 'application/x-www-form-urlencoded',\n      ), FALSE);\n      if ($csrf_required) {\n        $params['@code'] = 400;\n        $this->assertEqual($result['code'], $params['@code'], format_string('@code on @method without CSRF token for @role user.', $params));\n      }\n      else {\n        $this->assertTrue($result['code'] >= 200 && $result['code'] <= 204, format_string('@method without CSRF token for @role user is allowed.', $params));\n      }\n\n      // Invalid CSRF token.\n      $result = $this->httpRequest($this->getPath($method), $method, $request, array(\n        'Content-Type' => 'application/x-www-form-urlencoded',\n        'X-CSRF-Token' => 'invalidToken',\n      ), FALSE);\n      if ($csrf_required) {\n        $params['@code'] = 403;\n        $this->assertEqual($result['code'], $params['@code'], format_string('@code on @method with invalid CSRF token for @role user.', $params));\n      }\n      else {\n        $this->assertTrue($result['code'] >= 200 && $result['code'] <= 204, format_string('@method with invalid CSRF token for @role user is allowed.', $params));\n      }\n\n      // Valid CSRF token.\n      $result = $this->httpRequest($this->getPath($method), $method, $request, array(\n        'Content-Type' => 'application/x-www-form-urlencoded',\n      ));\n      $this->assertTrue($result['code'] >= 200 && $result['code'] <= 204, format_string('@method allowed with CSRF token for @role user.', $params));\n    }\n  }\n\n  /**\n   * Get the path for the request.\n   *\n   * For non \"POST\" methods, a new node is created.\n   *\n   * @param $method\n   *   The HTTP method.\n   *\n   * @return string\n   *   The path for the request.\n   */\n  protected function getPath($method) {\n    if ($method == RequestInterface::METHOD_POST) {\n      return 'api/v1.0/articles';\n    }\n    $settings = array(\n      'type' => 'article',\n      'title' => $this->randomString(),\n    );\n    $node = $this->drupalCreateNode($settings);\n    return 'api/v1.0/articles/' . $node->nid;\n  }\n}\n"
  },
  {
    "path": "tests/RestfulCurlBaseTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains \\RestfulCurlBaseTestCase\n */\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulCurlBaseTestCase extends DrupalWebTestCase {\n\n  /**\n   * Helper function to issue a HTTP request with simpletest's cURL.\n   *\n   * Copied and slightly adjusted from the RestWS module.\n   *\n   * @param string $url\n   *   The URL of the request.\n   * @param string $method\n   *   The HTTP method of the request. Defaults to \"GET\".\n   * @param array $body\n   *   Either the body for POST and PUT or additional URL parameters for GET.\n   * @param array $headers\n   *   Additional HTTP header parameters.\n   * @param bool $use_token\n   *   Determines if a CSRF token should be retrieved by default for write\n   *   operations for logged in users. Defaults to TRUE.\n   *\n   * @return array\n   *   Array keyed with the \"code\", \"headers\", and \"body\" of the response.\n   */\n  protected function httpRequest($url, $method = RequestInterface::METHOD_GET, $body = NULL, $headers = array(), $use_token = TRUE) {\n    $format = 'json';\n    $curl_options = array();\n\n    switch ($method) {\n      case RequestInterface::METHOD_GET:\n        // Set query if there are addition GET parameters.\n        $options = isset($body) ? array('absolute' => TRUE, 'query' => $body) : array('absolute' => TRUE);\n        $curl_options = array(\n          CURLOPT_HTTPGET => TRUE,\n          CURLOPT_URL => url($url, $options),\n          CURLOPT_NOBODY => FALSE,\n        );\n        break;\n\n      case RequestInterface::METHOD_HEAD:\n      case RequestInterface::METHOD_OPTIONS:\n        // Set query if there are addition GET parameters.\n        $options = isset($body) ? array('absolute' => TRUE, 'query' => $body) : array('absolute' => TRUE);\n        $curl_options = array(\n          CURLOPT_HTTPGET => FALSE,\n          CURLOPT_CUSTOMREQUEST => $method,\n          CURLOPT_URL => url($url, $options),\n          CURLOPT_NOBODY => FALSE,\n        );\n        break;\n\n      case RequestInterface::METHOD_POST:\n        $curl_options = array(\n          CURLOPT_HTTPGET => FALSE,\n          CURLOPT_POST => TRUE,\n          CURLOPT_POSTFIELDS => is_array($body) ? http_build_query($body) : $body,\n          CURLOPT_URL => url($url, array('absolute' => TRUE)),\n          CURLOPT_NOBODY => FALSE,\n        );\n        if (empty($headers['Content-Type'])) {\n          $headers['Content-Type'] = 'application/' . $format;\n        }\n        break;\n\n      case RequestInterface::METHOD_PUT:\n      case RequestInterface::METHOD_PATCH:\n        $curl_options = array(\n          CURLOPT_HTTPGET => FALSE,\n          CURLOPT_CUSTOMREQUEST => $method,\n          CURLOPT_POSTFIELDS => is_array($body) ? http_build_query($body) : $body,\n          CURLOPT_URL => url($url, array('absolute' => TRUE)),\n          CURLOPT_NOBODY => FALSE,\n        );\n        if (empty($headers['Content-Type'])) {\n          $headers['Content-Type'] = 'application/' . $format;\n        }\n        break;\n\n      case RequestInterface::METHOD_DELETE:\n        $curl_options = array(\n          CURLOPT_HTTPGET => FALSE,\n          CURLOPT_CUSTOMREQUEST => RequestInterface::METHOD_DELETE,\n          CURLOPT_URL => url($url, array('absolute' => TRUE)),\n          CURLOPT_NOBODY => FALSE,\n        );\n        break;\n    }\n\n    $curl_options += array(CURLOPT_HTTPHEADER => array());\n\n    if (Request::isWriteMethod($method) && $use_token) {\n      // Add CSRF token for write operations.\n      if (empty($this->csrfToken)) {\n        $response = $this->drupalGet('api/session/token');\n        $result = drupal_json_decode($response);\n        if (!empty($result['X-CSRF-Token'])) {\n          $this->csrfToken = $result['X-CSRF-Token'];\n          $headers['X-CSRF-Token'] = $result['X-CSRF-Token'];\n        }\n      }\n      else {\n        $headers['X-CSRF-Token'] = $this->csrfToken;\n      }\n    }\n\n    foreach ($headers as $key => $value) {\n      $curl_options[CURLOPT_HTTPHEADER][] = $key . ': ' . $value;\n    }\n\n    $response = $this->curlExec($curl_options);\n    $response_headers = array();\n    foreach ($this->drupalGetHeaders() as $header_name => $header_value) {\n      $response_headers[] = $header_name .  ': ' . $header_value;\n    }\n    $response_headers = implode(\"\\n\", $response_headers);\n\n    $code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);\n\n    $this->verbose($method . ' request to: ' . $url .\n      '<hr />Code: ' . $code .\n      '<hr />Response headers: ' . $response_headers .\n      '<hr />Response body: ' . $response);\n\n    return array(\n      'code' => $code,\n      'headers' => $response_headers,\n      'body' => $response,\n    );\n  }\n}\n"
  },
  {
    "path": "tests/RestfulDataProviderPlugPluginsTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains \\RestfulDataProviderCToolsPluginsTestCase.\n */\n\nuse Drupal\\restful\\Exception\\ForbiddenException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulDataProviderPlugPluginsTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Plug plugins',\n      'description' => 'Test the Plug plugins data provider.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example');\n  }\n\n  /**\n   * Test the data provider.\n   */\n  public function testDataProvider() {\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPlugin('discovery:1.0');\n\n    // Assert sorting and filtering works as expected.\n    $request = array(\n      // Get all resources.\n      'all' => TRUE,\n      'sort' => '-name',\n      'filter' => array(\n        'minorVersion' => array(\n          'value' => '4',\n          'operator' => '>=',\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('', $request));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(count($result), 4, 'Discovery filtered resources correctly.');\n    $this->assertTrue($result[0]['name'] = 'articles_1_7' && $result[1]['name'] = 'articles_1_6' && $result[2]['name'] = 'articles_1_5' && $result[2]['name'] = 'articles_1_4', 'Discovery sorted resources correctly.');\n\n    // Assert sorting and filtering works as expected.\n    $request = array(\n      // Get all resources.\n      'filter' => array(\n        'resource' => array(\n          'value' => 'articles',\n          'operator' => '=',\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('', $request));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(count($result), 1, 'Latest resources shown by default.');\n\n    $request = array(\n      // Get all resources.\n      'filter' => array(\n        'resource' => array(\n          'value' => 'articles',\n          'operator' => '=',\n        ),\n      ),\n      'all' => 1,\n    );\n    $handler->setRequest(Request::create('', $request));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertTrue(count($result) > 1, 'All resources shown by passing the \"all\" query string.');\n\n    // Assert sorting and filtering works as expected.\n    $request = array(\n      // Get all resources.\n      'filter' => array(\n        'resource' => array(\n          'value' => 'discovery',\n          'operator' => '=',\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('', $request));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(count($result), 0, 'Resources without discovery are ignored.');\n\n    // Make sure that unauthorized users cannot enable/disable resources via the\n    // API.\n    $handler->setAccount(drupal_anonymous_user());\n    $handler->setRequest(Request::create('api/v1.0/discovery/articles:1.0', array(), RequestInterface::METHOD_DELETE));\n    $handler->setPath('articles:1.0');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Un-privileged user can disable endpoints.');\n    }\n    catch (ForbiddenException $e) {\n      $this->pass('Un-privileged user cannot disable endpoints.');\n    }\n    $handler->setRequest(Request::create('api/v1.0/discovery/articles:1.0', array(), RequestInterface::METHOD_PUT, NULL, FALSE, NULL, array(), array(), array(), array('enable' => 1)));\n    $handler->setPath('articles:1.0');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Un-privileged user can enable endpoints.');\n    }\n    catch (ForbiddenException $e) {\n      $this->pass('Un-privileged user cannot enable endpoints.');\n    }\n\n    // Make sure that authorized users can enable/disable resources via the API.\n    $account = $this->drupalCreateUser(array('administer restful resources'));\n    $handler->setAccount($account);\n    $handler->setRequest(Request::create('api/v1.0/discovery/articles:1.0', array(), RequestInterface::METHOD_DELETE));\n    $handler->setPath('articles:1.0');\n    $handler->process();\n    $resource = $resource_manager->getPlugin('articles:1.0');\n    $this->assertNull($resource, 'Plugin disabled via the API.');\n    $handler->setRequest(Request::create('api/v1.0/discovery/articles:1.0', array(), RequestInterface::METHOD_PUT, NULL, FALSE, NULL, array(), array(), array(), array('enable' => 1)));\n    $handler->setPath('articles:1.0');\n    $handler->process();\n    $resource = $resource_manager->getPlugin('articles:1.0');\n    $this->assertTrue($resource->isEnabled(), 'Plugin enabled via the API.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulDbQueryTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulDbQueryTestCase.\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulDbQueryTestCase extends DrupalWebTestCase {\n\n  /**\n   * The name of the test table.\n   *\n   * @var string\n   */\n  protected $tableName = 'restful_test_db_query';\n\n  /**\n   * Provides information about the test class.\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'DB Query',\n      'description' => 'Test the DB Query data provider.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * Operations before the testing begins.\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test authenticating a user.\n   */\n  public function testCrudOperations() {\n    $resource_manager = restful()->getResourceManager();\n    $random_int = intval(mt_rand(1, 100));\n    $random_string = $this->randomName();\n    $random_serialized = serialize(array(\n      'key1' => $random_int,\n      'key2' => $random_string,\n    ));\n\n    // Populate the table with some values.\n    $mock_data = array(\n      'str_field' => $random_string,\n      'int_field' => $random_int,\n      'serialized_field' => $random_serialized,\n    );\n    $id = db_insert($this->tableName)\n      ->fields($mock_data)\n      ->execute();\n    $id = intval($id);\n\n    $this->assertTrue(!empty($id), 'The manual record could be inserted');\n\n    // Get the handler.\n    $handler = $resource_manager->getPlugin('db_query_test:1.0');\n\n    // Testing read context.\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id));\n    $handler->setPath($id);\n    $result = $handler->process();\n    /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollection $collection */\n    $collection = $result[0];\n    $this->assertEqual($collection->get('string')\n      ->value($collection->getInterpreter()), $mock_data['str_field'], 'The record was retrieved successfully.');\n    $this->assertEqual($collection->get('integer')\n      ->value($collection->getInterpreter()), $mock_data['int_field'], 'The record was retrieved successfully.');\n    $this->assertEqual($collection->get('serialized')\n      ->value($collection->getInterpreter()), $mock_data['serialized_field'], 'The record was retrieved successfully.');\n\n    // Testing JSON API formatter.\n    $formatter_manager = restful()->getFormatterManager();\n    $formatter_manager->setResource($handler);\n    $result = drupal_json_decode($formatter_manager->format($handler->process(), 'json_api'));\n    $this->assertEqual($result['data']['attributes']['string'], $mock_data['str_field'], 'The record was retrieved successfully.');\n    $this->assertEqual($result['data']['attributes']['integer'], $mock_data['int_field'], 'The record was retrieved successfully.');\n    $this->assertEqual($result['data']['attributes']['serialized'], $mock_data['serialized_field'], 'The record was retrieved successfully.');\n\n    // Testing update context.\n    $mock_data2 = array(\n      'string' => $this->randomName(),\n    );\n\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id, array(), RequestInterface::METHOD_PATCH, NULL, FALSE, NULL, array(), array(), array(), $mock_data2));\n    $handler->setPath($id);\n    $handler->process();\n    // Now get the updated object.\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id));\n    $handler->setPath($id);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n\n    $expected = array(\n      // ID should be unchanged.\n      'id' => $id,\n      // String should be the string that we updated.\n      'string' => $mock_data2['string'],\n      // Serialized value should be unchanged.\n      'serialized' => $random_serialized,\n      // Integer value should be unchanged.\n      'integer' => $random_int,\n    );\n\n    // We expect that only the string field has changed.\n    $this->assertEqual($result['data'][0], $expected, 'The record was updated with PUT successfully.');\n\n\n    // Testing replace context.\n    $mock_data3 = array(\n      'string' => $this->randomName(),\n    );\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id, array(), RequestInterface::METHOD_PUT, NULL, FALSE, NULL, array(), array(), array(), $mock_data3));\n    $handler->setPath($id);\n    $handler->process();\n    // Now get the updated object.\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id));\n    $handler->setPath($id);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n\n    $expected = array(\n      // ID should be unchanged.\n      'id' => $id,\n      // String should be the string that we PUT.\n      'string' => $mock_data3['string'],\n      // Serialized field should be null.\n      'serialized' => 'N;',\n      // Integer field should be default value from schema.\n      'integer' => 0,\n    );\n\n    // We expect that only the supplied fields are present.\n    $this->assertEqual($result['data'][0], $expected, 'The record was updated with PATCH successfully.');\n\n    // Testing delete context.\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id, array(), RequestInterface::METHOD_DELETE));\n    $handler->setPath($id);\n    $handler->process();\n    $count = db_select($this->tableName)\n      ->countQuery()\n      ->execute()\n      ->fetchField();\n    $this->assertEqual($count, 0, 'The record was deleted successfully.');\n\n    // Testing create context.\n    $mock_data4 = array(\n      'string' => $random_string,\n      'integer' => $random_int,\n      'serialized' => array(\n        'key1' => $random_int,\n        'key2' => $random_string,\n      ),\n    );\n    $handler->setRequest(Request::create('api/db_query_test/v1.0', array(), RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $mock_data4));\n    $handler->setPath('');\n    $handler->process();\n\n    $count = db_select($this->tableName)\n      ->countQuery()\n      ->execute()\n      ->fetchField();\n    $this->assertEqual($count, 1, 'The record was created.');\n\n    // Testing listing for read context.\n    $handler->setRequest(Request::create('api/db_query_test/v1.0'));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n\n    // The created record should match our input.\n    $expected = $mock_data4;\n    // Account for serialization.\n    $expected['serialized'] = $random_serialized;\n    // Account for not knowing the ID of the new entity beforehand.\n    unset($result['data'][0]['id']);\n\n    $this->assertEqual($result['data'][0], $expected, 'All the content listed successfully.');\n\n    // Testing filters.\n    $mock_data5 = array(\n      'str_field' => $this->randomName(),\n      'int_field' => 101,\n    );\n    $mock_data5['serialized_field'] = serialize($mock_data5);\n    db_insert($this->tableName)\n      ->fields($mock_data5)\n      ->execute();\n\n    $mock_data6 = array(\n      'str_field' => $this->randomName(),\n      'int_field' => 102,\n    );\n    $mock_data6['serialized_field'] = serialize($mock_data6);\n    db_insert($this->tableName)\n      ->fields($mock_data6)\n      ->execute();\n\n    $parsed_input = array(\n      'filter' => array(\n        'integer' => array(\n          'value' => array(101, 102),\n          'conjunction' => 'OR',\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('api/db_query_test/v1.0', $parsed_input));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $this->assertEqual(count($result['data']), 2);\n    $parsed_input = array(\n      'filter' => array(\n        'integer' => array(\n          'value' => array(101, 102),\n          'operator' => array('=', '>='),\n          'conjunction' => 'OR',\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('api/db_query_test/v1.0', $parsed_input));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $this->assertEqual(count($result['data']), 2);\n  }\n\n  /**\n   * Test the render cache.\n   */\n  public function __testRenderCache() {\n    $resource_manager = restful()->getResourceManager();\n    $account = $this->drupalCreateUser();\n\n    // Populate the table with some values.\n    $mock_data = array(\n      'str_field' => $this->randomName(),\n      'int_field' => intval(mt_rand(1, 100)),\n    );\n    $mock_data['serialized_field'] = serialize($mock_data);\n    $id = db_insert($this->tableName)\n      ->fields($mock_data)\n      ->execute();\n    $id = intval($id);\n\n    // Get the handler.\n    /* @var \\Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResourceInterface $handler */\n    $handler = $resource_manager->getPlugin('db_query_test:1.0');\n    $handler->setAccount($account);\n    $cache = $handler->getCacheController();\n\n    // Populate the cache entry.\n    $handler->setRequest(Request::create('api/db_query_test/v1.0/' . $id));\n    $handler->setPath($id);\n    $handler->process();\n    $version = $handler->getVersion();\n    $cid = 'v' . $version['major'] . '.' . $version['minor'] . '::db_query_test::uu' . $account->uid . '::patb:restful_test_db_query::cl:id::id:' . $id;\n    $cache_data = $cache->get($cid);\n    $this->assertNotNull($cache_data->data, 'Cache data is present.');\n\n    $this->assertEqual($cache_data->data[0]['string'], $mock_data['str_field'], 'The record was retrieved successfully.');\n    $this->assertEqual($cache_data->data[0]['integer'], $mock_data['int_field'], 'The record was retrieved successfully.');\n    $this->assertEqual($cache_data->data[0]['serialized'], $mock_data['serialized_field'], 'The record was retrieved successfully.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulDiscoveryTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulDiscoveryTestCase\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\n/**\n * Class RestfulDiscoveryTestCase.\n */\nclass RestfulDiscoveryTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Discovery',\n      'description' => 'Test the discovery features.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test the discovery page.\n   */\n  public function testDiscoveryPage() {\n    $request = $this->httpRequest('api');\n    $body = drupal_json_decode($request['body']);\n    $this->assertTrue(!empty($body['self']), 'The discovery plugin exposed the plugins.');\n\n    // Disable the plugin and test a 404.\n    variable_set('restful_enable_discovery_resource', FALSE);\n    $request = $this->httpRequest('api');\n    $body = drupal_json_decode($request['body']);\n    $this->assertEqual($body['status'], 404, 'The discovery plugin is disabled.');\n    variable_set('restful_enable_discovery_resource', TRUE);\n  }\n\n  /**\n   * Test the headers populated in an OPTIONS request.\n   */\n  public function testOptionsMethod() {\n    // 1. Assert Access-Control-Allow-Methods.\n    $response = $this->httpRequest('api/v1.4/test_articles', RequestInterface::METHOD_OPTIONS);\n    $this->assertTrue(strpos($response['headers'], sprintf('access-control-allow-methods: %s', implode(', ', array(\n        RequestInterface::METHOD_HEAD,\n        RequestInterface::METHOD_OPTIONS,\n      )))) !== FALSE, 'Access-Control-Allow-Methods header is populated correctly.');\n    // Make sure it returns the appropriate headers for every path.\n    $response = $this->httpRequest('api/v1.4/test_articles/1', RequestInterface::METHOD_OPTIONS);\n    $this->assertTrue(strpos($response['headers'], sprintf('access-control-allow-methods: %s', implode(', ', array(\n        RequestInterface::METHOD_PATCH,\n        RequestInterface::METHOD_DELETE,\n        RequestInterface::METHOD_OPTIONS,\n      )))) !== FALSE, 'Access-Control-Allow-Methods header is populated correctly for different paths.');\n\n    // 2. Assert Accept.\n    // List the content types the route accepts.\n    $this->assertTrue(strpos($response['headers'], 'accept: application/xml; charset=utf-8') !== FALSE, 'Accept header is populated correctly for configured formatter.');\n    $response = $this->httpRequest('api/v1.2/test_articles', RequestInterface::METHOD_OPTIONS);\n\n    $this->assertTrue(strpos($response['headers'], 'application/hal+json') !== FALSE, 'Accept header is populated correctly for non configured formatters.');\n    $this->assertTrue(strpos($response['headers'], 'application/json') !== FALSE, 'Accept header is populated correctly for non configured formatters.');\n    $this->assertTrue(strpos($response['headers'], 'application/vnd.api+json') !== FALSE, 'Accept header is populated correctly for non configured formatters.');\n    $this->assertTrue(strpos($response['headers'], 'application/drupal.single+json') !== FALSE, 'Accept header is populated correctly for non configured formatters.');\n    $this->assertTrue(strpos($response['headers'], 'application/xml') !== FALSE, 'Accept header is populated correctly for non configured formatters.');\n\n    // 3. Assert Access-Control-Allow-Origin.\n    $response = $this->httpRequest('api/v1.4/test_articles', RequestInterface::METHOD_HEAD);\n    $this->assertTrue(strpos($response['headers'], 'access-control-allow-origin: *') !== FALSE, 'Accept header is populated correctly for non configured formatters.');\n\n    // 4. Assert Access.\n    $response = $this->httpRequest('api/v1.4/test_articles/1', RequestInterface::METHOD_HEAD);\n    $this->assertTrue($response['code'], 400, 'Access is denied for unsupported HTTP methods.');\n  }\n\n  /**\n   * Field discovery.\n   */\n  public function testFieldDiscovery() {\n    // Add common fields, vocabulary and terms.\n    restful_test_add_fields();\n    // Create an entity.\n    $entity = entity_create('entity_test', array('name' => 'main', 'label' => $this->randomName()));\n    $pid = $entity->save();\n    $handler = restful()->getResourceManager()->getPlugin('main:1.1');\n    $handler->setRequest(Request::create('api/v1.1/main/' . $pid, array(), RequestInterface::METHOD_OPTIONS));\n    $handler->setPath($pid);\n    $formatter = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL);\n    $formatter->setResource($handler);\n    $result = $formatter->prepare($handler->process());\n    $expected = array(\n      'id' => array(\n        'data' => array(\n          'cardinality' => 1,\n          'read_only' => TRUE,\n          'type' => 'integer',\n          'required' => TRUE,\n        ),\n        'info' => array(\n          'description' => t('Base ID for the entity.'),\n          'label' => t('ID'),\n        ),\n      ),\n      'label' => array(\n        'data' => array(\n          'cardinality' => 1,\n          'read_only' => FALSE,\n          'type' => 'string',\n          'required' => FALSE,\n          'size' => 255,\n        ),\n        'form_element' => array(\n          'allowed_values' => NULL,\n          'type' => 'textfield',\n          'default_value' => '',\n          'placeholder' => '',\n          'size' => 255,\n          'description' => 'The label of the resource.',\n          'title' => 'label',\n        ),\n        'info' => array(\n          'description' => t('The label of the resource.'),\n          'label' => t('Label'),\n        ),\n      ),\n      'text_multiple' => array(\n        'data' => array(\n          'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n          'read_only' => FALSE,\n          'type' => 'string',\n          'size' => 255,\n          'required' => FALSE,\n        ),\n        'form_element' => array(\n          'allowed_values' => NULL,\n          'default_value' => '',\n          'placeholder' => t('This is helpful.'),\n          'size' => 255,\n          'type' => 'textfield',\n          'description' => 'This field holds different text inputs.',\n          'title' => 'text_multiple',\n        ),\n        'info' => array(\n          'description' => t('This field holds different text inputs.'),\n          'label' => t('Text multiple'),\n        ),\n      ),\n    );\n\n    foreach ($expected as $public_field => $discovery_info) {\n      foreach (array('data', 'form_element', 'info') as $section_name) {\n        if (empty($result['data'][0][$public_field][$section_name]) && empty($expected[$public_field][$section_name])) {\n          continue;\n        }\n        $this->assertEqual($result['data'][0][$public_field][$section_name], $expected[$public_field][$section_name], format_string('The \"@section\" information is properly described for @field.', array(\n          '@field' => $public_field,\n          '@section' => $section_name,\n        )));\n      }\n    }\n  }\n\n  /**\n   * Field discovery allowed values.\n   */\n  public function testFieldDiscoveryAllowedValues() {\n    // Add entity reference fields.\n    restful_test_add_fields('node', 'article');\n\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.2');\n    // Create 3 nodes.\n    $expected_result = array();\n    foreach (array(1, 2, 3) as $id) {\n      $title = 'article/' . $id;\n      $settings = array(\n        'title' => $title,\n        'type' => 'article',\n\n      );\n      $node = $this->drupalCreateNode($settings);\n      $expected_result[$node->nid] = $title;\n    }\n\n    // Set widget to select list.\n    $instance = field_info_instance('node', 'entity_reference_single', 'article');\n    $instance['widget']['type'] = 'options_select';\n    field_update_instance($instance);\n\n    $handler->setRequest(Request::create('api/v1.2/test_articles', array(), RequestInterface::METHOD_OPTIONS));\n    $handler->setPath('');\n    $formatter = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL);\n    $formatter->setResource($handler);\n    $result = $formatter->prepare($handler->process());\n    $this->assertEqual($result['data'][0]['entity_reference_single']['form_element']['allowed_values'], $expected_result);\n\n    // Set widget to autocomplete.\n    $instance['widget']['type'] = 'entityreference_autocomplete';\n    field_update_instance($instance);\n\n    // Invalidate public fields cache.\n    $handler = restful()->getResourceManager()->getPluginCopy('test_articles:1.2');\n\n    $handler->setRequest(Request::create('api/v1.2/test_articles', array(), RequestInterface::METHOD_OPTIONS));\n    $handler->setPath('');\n    $formatter = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL);\n    $formatter->setResource($handler);\n    $result = $formatter->prepare($handler->process());\n    $this->assertNull($result['data'][0]['entity_reference_single']['form_element']['allowed_values']);\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulEntityAndPropertyAccessTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulEntityAndPropertyAccessTestCase\n */\n\nuse Drupal\\restful\\Exception\\ForbiddenException;\n\nclass RestfulEntityAndPropertyAccessTestCase extends DrupalWebTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Entity and property access',\n      'description' => 'Test access for the entity and the properties.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test access control for creating an entity.\n   */\n  public function testCreateAccess() {\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.0');\n    $parsed_body = array('label' => $this->randomName());\n\n    // Non-privileged user.\n    $user1 = $this->drupalCreateUser();\n    try {\n      $handler->setAccount($user1);\n      $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_POST, $handler, $parsed_body);\n      $this->fail('Non-privileged user can create entity.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-privileged user cannot create entity.');\n    }\n\n    // Privileged user.\n    $user2 = $this->drupalCreateUser(array('create article content'));\n    $handler->setAccount($user2);\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_POST, $handler, $parsed_body);\n    $this->assertTrue($result['data'][0], 'Privileged user can create entity.');\n\n    // Privileged user, with limited access to property.\n    restful_test_deny_access_field();\n    $handler->setAccount($user2);\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_POST, $handler, $parsed_body);\n    $this->assertTrue($result['data'][0], 'Privileged user can create entity, with limited access to property.');\n\n    // Privileged user, with limited access to property, and that property\n    // passed in the request.\n    $text1 = $this->randomName();\n    $parsed_body['body'] = $text1;\n\n    try {\n      $handler->setAccount($user1);\n      $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_POST, $handler, $parsed_body);\n      $this->fail('Non-privileged user can create entity with inaccessible property that was passed in the request.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-privileged user cannot create entity with inaccessible property that was passed in the request.');\n    }\n    restful_test_clear_access_field();\n  }\n\n  /**\n   * Test access control for updating an entity.\n   */\n  public function testUpdateAccess() {\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n\n    $settings = array(\n      'type' => 'article',\n      'title' => $label,\n    );\n\n    $node = $this->drupalCreateNode($settings);\n    $id = $node->nid;\n\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.0');\n    $parsed_body = array('label' => $new_label);\n\n    // Non-privileged user.\n    $user1 = $this->drupalCreateUser();\n    try {\n      $handler->setAccount($user1);\n      $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_PUT, $handler, $parsed_body, $id);\n      $this->fail('Non-privileged user can update entity.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-privileged user cannot update entity.');\n    }\n\n    // Privileged user.\n    $user2 = $this->drupalCreateUser(array('edit any article content'));\n    $handler->setAccount($user2);\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_PUT, $handler, $parsed_body, $id);\n    $this->assertTrue($result['data'][0], 'Privileged user can update entity.');\n    $this->assertEqual($result['data'][0]['id'], $id, 'Updated entity has the same entity ID.');\n    $this->assertEqual($result['data'][0]['label'], $new_label, 'Entity label was updated.');\n\n    // Privileged user, with limited access to property.\n    restful_test_deny_access_field();\n    $handler->setAccount($user2);\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_PUT, $handler, $parsed_body, $id);\n    $this->assertTrue($result['data'][0], 'Privileged user can update entity, with limited access to property.');\n\n    // Privileged user, with limited access to property, and that property\n    // passed in the request.\n    $text1 = $this->randomName();\n    $parsed_body['body'] = $text1;\n\n    try {\n      $handler->setAccount($user1);\n      $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_PUT, $handler, $parsed_body, $id);\n      $this->fail('Non-privileged user can update entity with inaccessible property that was passed in the request.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-privileged user cannot update entity with inaccessible property that was passed in the request.');\n    }\n    restful_test_clear_access_field();\n  }\n\n  /**\n   * Test access control for viewing an entity.\n   */\n  public function testViewAccess() {\n    $user1 = $this->drupalCreateUser();\n    $label = $this->randomName();\n    $settings = array(\n      'type' => 'article',\n      'title' => $label,\n      'uid' => $user1->uid,\n    );\n    $node1 = $this->drupalCreateNode($settings);\n    $wrapper = entity_metadata_wrapper('node' ,$node1);\n\n    $wrapper->body->set(array('value' => $this->randomName()));\n    $wrapper->save();\n\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.2');\n\n    // Privileged user.\n    $handler->setAccount($user1);\n    $response = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_GET, $handler, array(), $node1->nid);\n    $result = $response['data'][0];\n    $this->assertTrue($result['body'], 'Privileged user can view entity.');\n\n    // Privileged user, with limited access to property.\n    restful_test_deny_access_field();\n    $handler->setAccount($user1);\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_GET, $handler, array(), $node1->nid);\n    $this->assertTrue(!isset($result['data'][0]['body']), 'Privileged user can view entity but without inaccessible properties.');\n    restful_test_clear_access_field();\n\n    // Non-privileged user (Revoke \"access content\" permission).\n    user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));\n    $user2 = drupal_anonymous_user();\n    try {\n      $handler->setAccount($user2);\n      $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_GET, $handler, array(), $node1->nid);\n      $this->fail('Non-privileged user can view entity.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-privileged user cannot view entity.');\n    }\n  }\n\n  /**\n   * Tests custom access callbacks at the resource method level.\n   */\n  public function testEndPointAccessCallback() {\n    $settings = array(\n      'type' => 'article',\n    );\n    $node = $this->drupalCreateNode($settings);\n\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.3');\n    try {\n      $handler->doGet($node->nid);\n      $this->fail('Custom access callback per resource\\'s method not executed correctly.');\n    }\n    catch (ForbiddenException $e) {\n      $this->pass('Custom access callback per endpoint executed correctly.');\n    }\n\n    $handler->setPath($node->nid);\n    $handler->setRequest(\\Drupal\\restful\\Http\\Request::create($handler->versionedUrl($node->nid, array('absolute' => FALSE)), array(), \\Drupal\\restful\\Http\\RequestInterface::METHOD_HEAD));\n    $handler->process();\n    $this->pass('Custom access callback per endpoint executed correctly.');\n  }\n\n  /**\n   * Test access callback per public field.\n   */\n  public function testPublicFieldAccess() {\n    $settings = array(\n      'title' => 'no access',\n      'type' => 'article',\n    );\n    $node = $this->drupalCreateNode($settings);\n    $handler = restful()->getResourceManager()->getPlugin('test_articles:1.0');\n\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_GET, $handler, array(), $node->nid);\n    $this->assertNotNull($result['data'][0]['label'], 'Label access is allowed without access callback.');\n\n    variable_set('restful_test_revoke_public_field_access', 'label');\n    $handler = restful()->getResourceManager()->getPluginCopy('test_articles:1.0');\n\n    $result = $this->doRequest(\\Drupal\\restful\\Http\\RequestInterface::METHOD_GET, $handler, array(), $node->nid);\n    $this->assertTrue(empty($result['data'][0]['label']), 'Label access is denied with access callback.');\n  }\n\n  /**\n   * Helper method to format a request.\n   *\n   * @param string $method\n   *   The HTTP verb.\n   * @param \\Drupal\\restful\\Plugin\\resource\\ResourceInterface $handler\n   *   The handler.\n   * @param array $input\n   *   The parsed body array.\n   * @param string $path\n   *   The path where to make the request.\n   *\n   * @return array\n   *   The formatted output.\n   */\n  protected function doRequest($method, \\Drupal\\restful\\Plugin\\resource\\ResourceInterface $handler, array $input = array(), $path = '') {\n    $output = NULL;\n    if ($method == \\Drupal\\restful\\Http\\RequestInterface::METHOD_POST) {\n      $output = $handler->doPost($input);\n    }\n    elseif ($method == \\Drupal\\restful\\Http\\RequestInterface::METHOD_PUT) {\n      $output = $handler->doPut($path, $input);\n    }\n    elseif ($method == \\Drupal\\restful\\Http\\RequestInterface::METHOD_PATCH) {\n      $output = $handler->doPatch($path, $input);\n    }\n    elseif ($method == \\Drupal\\restful\\Http\\RequestInterface::METHOD_GET) {\n      $output = $handler->doGet($path, $input);\n    }\n    if (!isset($output)) {\n      return NULL;\n    }\n    $formatter = restful()->getFormatterManager()->negotiateFormatter(NULL, 'json');\n    $formatter->setResource($handler);\n    return $formatter->prepare($output);\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulEntityUserAccessTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulEntityUserAccessTestCase.\n */\n\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Http\\Request;\n\n/**\n * Class RestfulEntityUserAccessTestCase.\n */\nclass RestfulEntityUserAccessTestCase extends DrupalWebTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'User resource access',\n      'description' => 'Test access to the base \"users\" resource.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful');\n  }\n\n  /**\n   * Test access control for viewing the \"users\" resource.\n   */\n  public function testViewAccess() {\n    $resource_manager = restful()->getResourceManager();\n    $user1 = $this->drupalCreateUser();\n    $user2 = $this->drupalCreateUser(array('access user profiles'));\n\n    // Non-privileged user.\n    $handler = $resource_manager->getPlugin('users:1.0');\n    $handler->setAccount($user1);\n\n    try {\n      $handler->setRequest(Request::create('api/v1.0/users/' . $user2->uid));\n      $handler->setPath($user2->uid);\n      $handler->process();\n      $this->fail('Non-privileged user can view another user.');\n    }\n    catch (InaccessibleRecordException $e) {\n      $this->pass('Non-privileged user cannot view another user.');\n    }\n    catch (\\Exception $e) {\n      $this->fail('Incorrect exception thrown for non-privileged user accessing another user.');\n    }\n\n    // Listing of users.\n    $handler->setRequest(Request::create('api/v1.0/users'));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['self'], url('api/v1.0/users/0', array('absolute' => TRUE)));\n    $this->assertEqual($result[1]['self'], url('api/v1.0/users/2', array('absolute' => TRUE)));\n    $this->assertEqual(count($result), 2, 'Unprivileged users can only see themselves and the anonymous user.');\n\n    // View own user account.\n    $handler->setRequest(Request::create('api/v1.0/users/' . $user1->uid));\n    $handler->setPath($user1->uid);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertEqual($result['mail'], $user1->mail, 'User can see own mail.');\n\n    // Privileged user, watching another user's profile.\n    $handler->setAccount($user2);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $expected_result = array(\n      'id' => $user1->uid,\n      'label' => $user1->name,\n      'self' => $handler->versionedUrl($user1->uid),\n    );\n\n    $this->assertEqual($result, $expected_result, \"Privileged user can access another user's resource.\");\n\n    // Listing of users.\n    $handler->setRequest(Request::create('api/v1.0/users'));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    // Check we have all the expected users count (user ID 1 and our declared\n    // users plus the anon user).\n    $this->assertTrue(count($result) == 4, 'Privileged user can access listing of users.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulEntityValidatorTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulEntityValidatorTestCase.\n */\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulEntityValidatorTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Entity validator',\n      'description' => 'Test integration with entity validator module.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test', 'entity_validator_example');\n  }\n\n  /**\n   * Test entity validator.\n   */\n  public function testEntityValidator() {\n    $user1 = $this->drupalCreateUser(array('create article content'));\n    $this->drupalLogin($user1);\n\n    $handler = restful()\n      ->getResourceManager()\n      ->getPlugin('test_articles:1.0');\n    $handler->setAccount($user1);\n\n    $parsed_body = array('title' => 'no', 'body' => 'Text with Drupal');\n\n    try {\n      $request = Request::create('', $parsed_body, RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $parsed_body);\n      $handler->setRequest($request);\n      $handler->process();\n      $this->fail('Too short title did not cause a \"Bad request\" error.');\n    }\n    catch (BadRequestException $e) {\n      $field_errors = $e->getFieldErrors();\n      $expected_result = array(\n        'title' => array(\n          'The title should be at least 3 characters long.',\n        ),\n      );\n\n      $this->assertEqual($field_errors, $expected_result, 'Correct error message passed in the JSON');\n    }\n\n    $parsed_body['title'] = 'yes';\n    $request = Request::create('', $parsed_body, RequestInterface::METHOD_POST, NULL, FALSE, NULL, array(), array(), array(), $parsed_body);\n    $handler->setRequest($request);\n    $result = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL, 'json')\n      ->prepare($handler->process());\n    $this->assertTrue($result['data'][0]['id'], 'Entity with proper title length passed validation and was created.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulExceptionHandleTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulExceptionHandleTestCase.\n */\n\n/**\n * Class RestfulExceptionHandleTestCase.\n */\nclass RestfulExceptionHandleTestCase extends \\RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Exception handling',\n      'description' => 'Test converting exceptions into JSON with code, message and description.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_example');\n  }\n\n  /**\n   * Test converting exceptions into JSON with code, message and description.\n   *\n   * When calling the API via hook_menu(), exceptions should be converted to a\n   * valid JSON.\n   */\n  public function testExceptionHandle() {\n    $options = array('sort' => 'wrong_key');\n    $result = $this->httpRequest('api/v1.0/articles', \\Drupal\\restful\\Http\\RequestInterface::METHOD_GET, $options);\n    $expected_result = array(\n      'type' => 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1',\n      'title' => 'The sort wrong_key is not allowed for this path.',\n      'status' => 400,\n      'detail' => 'Bad Request',\n    );\n    $this->assertEqual(drupal_json_decode($result['body']), $expected_result);\n    $this->assertEqual($result['code'], 400, 'Correct HTTP code.');\n  }\n\n  /**\n   * Test when an entity is not found that a 4XX is returned instead of 500.\n   */\n  public function testEntityNotFoundDelivery() {\n    $url = 'api/v1.0/articles/1';\n    $result = $this->httpRequest($url);\n    $body = drupal_json_decode($result['body']);\n    $this->assertEqual($result['code'], '422', format_string('422 status code sent for @url url.', array('@url' => $url)));\n    $this->assertTrue(strpos($result['headers'], 'application/problem+json;') !== FALSE, '\"application/problem+json\" found in invalid request.');\n    $this->assertEqual($body['title'], 'The entity ID 1 does not exist.', 'Correct error message.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulForbiddenItemsTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains \\RestfulForbiddenItemsTestCase.\n */\n\nuse Drupal\\restful\\Exception\\InaccessibleRecordException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldCollectionInterface;\n\n/**\n * Class RestfulForbiddenItemsTestCase.\n */\nclass RestfulForbiddenItemsTestCase extends DrupalWebTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Forbidden Items',\n      'description' => 'Tests handling access denied items.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n    restful_test_add_fields('node', 'article');\n  }\n\n  /**\n   * Tests access denied in lists and single elements.\n   */\n  public function testAccessDenied() {\n    $account = $this->drupalCreateUser();\n    $nids = $this->createEntityWithReferences($account->uid);\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPluginCopy('test_articles:1.2');\n    $handler->setAccount($account);\n\n    $this->assertTrue((bool) $handler->doGet($nids[2]));\n    restful_test_deny_access_node($nids[1]);\n    try {\n      $handler->doGet($nids[1]);\n      $this->fail('There should be a Forbidden exception.');\n    }\n    catch (InaccessibleRecordException $e) {\n      $this->assertEqual($e->getCode(), 404);\n      $this->assertEqual($e->getMessage(), InaccessibleRecordException::ERROR_404_MESSAGE);\n    }\n\n    variable_set('restful_show_access_denied', TRUE);\n    $handler = $resource_manager->getPluginCopy('test_articles:1.2');\n    $handler->setAccount($account);\n\n    $this->assertTrue((bool) $handler->doGet($nids[2]));\n    restful_test_deny_access_node($nids[1]);\n    try {\n      $handler->doGet($nids[1]);\n      $this->fail('There should be a Forbidden exception.');\n    }\n    catch (InaccessibleRecordException $e) {\n      $this->assertEqual($e->getCode(), 403);\n      $this->assertNotEqual($e->getMessage(), InaccessibleRecordException::ERROR_404_MESSAGE);\n    }\n\n    // When we include the related entities we are loading the referenced\n    // entity, that's when we check for the entity access. If we are only\n    // getting the list of IDs we don't know which entities will be accessible\n    // or not.\n    $handler = $resource_manager->getPluginCopy('test_articles:1.2');\n    $handler->setPath('');\n    $handler->setRequest(Request::create(NULL, array('include' => 'entity_reference_single,entity_reference_multiple')));\n    $handler->setAccount($account);\n    $response = $handler->process();\n    $returned_nids = array_map(function (ResourceFieldCollectionInterface $item) {\n      return $item->getIdField()->render($item->getInterpreter());\n    }, $response);\n    $this->assertTrue(count($response) == 2 && !in_array($nids[1], $returned_nids), 'Listing a denied node removes it from the listing.');\n    $formatter = restful()->getFormatterManager()->getPlugin('json_api');\n    $formatter->setResource($handler);\n    $results = $formatter->prepare($response);\n    $this->assertEqual(count($results['data'][0]['relationships']['entity_reference_multiple']['data']), 1, 'The inaccessible node is not present in the relationship.');\n\n    // Avoid count or pagination problems due to denied items.\n    $this->assertTrue(empty($results['links']['next']));\n\n    // Make sure that denied items in the related elements do not alter the top\n    // level count incorrectly.\n    $handler = $resource_manager->getPluginCopy('test_articles:1.2');\n    $handler->setPath('');\n    $handler->setRequest(Request::create(NULL, array(\n      'include' => 'entity_reference_single,entity_reference_multiple',\n    )));\n    $handler->setAccount($account);\n    $response = $handler->process();\n    $formatter->setResource($handler);\n    $results = $formatter->prepare($response);\n    $this->assertEqual(count($results['data'][0]['relationships']['entity_reference_multiple']['data']), 1, 'The count is not altered incorrectly.');\n    $this->assertEqual(count($results['meta']['denied']), 1, 'Denied elements are reported.');\n\n    // Same test without the includes should yield the same results.\n    $handler = $resource_manager->getPluginCopy('test_articles:1.2');\n    $handler->setPath('');\n    $handler->setRequest(Request::create(NULL, array(\n      'range' => 1,\n    )));\n    $handler->setAccount($account);\n    $response = $handler->process();\n    $formatter->setResource($handler);\n    $results = $formatter->prepare($response);\n    $this->assertEqual(count($results['data'][0]['relationships']['entity_reference_multiple']['data']), 1, 'Access checks are applied when the entity is not included.');\n    $this->assertTrue(empty($results['meta']['denied']), 'No denied item was detected.');\n  }\n\n  /**\n   * Adds some content to be retrieved.\n   *\n   * @param int $uid\n   *   The owner ID.\n   *\n   * @return int[]\n   *   The entity IDs.\n   */\n  protected function createEntityWithReferences($uid) {\n    $node1 = (object) array(\n      'title' => t('Node 1'),\n      'type' => 'article',\n      'uid' => $uid,\n    );\n    node_object_prepare($node1);\n    node_save($node1);\n\n    $node2 = (object) array(\n      'title' => t('Node 2'),\n      'type' => 'article',\n      'uid' => $uid,\n    );\n    node_object_prepare($node2);\n    node_save($node2);\n\n    $node3 = (object) array(\n      'title' => t('Node 3'),\n      'type' => 'article',\n      'uid' => $uid,\n    );\n    node_object_prepare($node3);\n    node_save($node3);\n\n    // Set some references to node1.\n    $wrapper = entity_metadata_wrapper('node', $node1);\n    $wrapper->entity_reference_single->set($node3);\n    $wrapper->entity_reference_multiple[] = $node2;\n    $wrapper->entity_reference_multiple[] = $node3;\n    $wrapper->save();\n\n    return array(\n      $node1->nid,\n      $node2->nid,\n      $node3->nid,\n    );\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulGetHandlersTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulGetHandlersTestCase\n */\nclass RestfulGetHandlersTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Get handlers',\n      'description' => 'Test getting handlers by version (major and minor).',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example');\n  }\n\n  /**\n   * Test getting handlers via API.\n   */\n  public function testGetHandlers() {\n    $resource_manager = restful()->getResourceManager();\n    $title = $this->randomName();\n    $settings = array(\n      'type' => 'article',\n      'title' => $title,\n    );\n    $node1 = $this->drupalCreateNode($settings);\n\n    $handler = $resource_manager->getPlugin('articles:1.1');\n    $this->assertTrue($handler instanceof \\Drupal\\restful_example\\Plugin\\resource\\node\\article\\v1\\Articles__1_0);\n    $handler->setRequest(\\Drupal\\restful\\Http\\Request::create('articles/v1.1/' . $node1->nid));\n    $handler->setPath($node1->nid);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertTrue(empty($result['self']), '\"self\" property does not appear in minor version 1.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulHalJsonTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulHalJsonTestCase\n */\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\HttpHeaderBag;\n\nclass RestfulHalJsonTestCase extends RestfulCurlBaseTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'View HAL+JSON',\n      'description' => 'Test the viewing of an entity in HAL+JSON format.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_test', 'entityreference');\n\n    restful_test_add_fields();\n  }\n\n  /**\n   * Test embedded resources.\n   */\n  public function testHalEmbeddedResources() {\n    $user1 = $this->drupalCreateUser();\n    /* @var \\Entity $entity1 */\n    $entity1 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $entity1->save();\n\n    /* @var \\Entity $entity2 */\n    $entity2 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $entity2->save();\n\n    $entity3 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper('entity_test', $entity3);\n\n    $text1 = $this->randomName();\n    $text2 = $this->randomName();\n\n\n    $wrapper->text_single->set($text1);\n    $wrapper->text_multiple->set(array($text1, $text2));\n\n    $wrapper->entity_reference_single->set($entity1);\n    $wrapper->entity_reference_multiple[] = $entity1;\n    $wrapper->entity_reference_multiple[] = $entity2;\n\n    $wrapper->save();\n\n    $handler = restful()->getResourceManager()->getPlugin('main:1.1');\n    $headers = new HttpHeaderBag(array(\n      'X-API-Version' => 'v1.1',\n      'Accept' => 'application/hal+json',\n    ));\n    $handler->setRequest(Request::create('api/main/' . $wrapper->getIdentifier(), array(), RequestInterface::METHOD_GET, $headers));\n    $handler->setPath($wrapper->getIdentifier());\n    $response = $handler->process();\n    $formatter_manager = restful()->getFormatterManager();\n    $formatter_manager->setResource($handler);\n    $formatter_result = $formatter_manager->format($response);\n    $results = drupal_json_decode($formatter_result);\n    $this->assertEqual(2, count($results['_embedded']));\n    $this->assertEqual($wrapper->entity_reference_multiple->count(), count($results['_embedded']['hal:entity_reference_multiple_resource']));\n    $this->assertEqual($entity1->pid, count($results['_embedded']['hal:entity_reference_single_resource']['id']));\n\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulHookMenuTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains \\RestfulHookMenuTestCase.\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulHookMenuTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * Overrides DrupalWebTestCase::getInfo().\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Menu API',\n      'description' => 'Test the hook_menu() and delivery callback implementations.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * Overrides DrupalWebTestCase::setUp().\n   */\n  public function setUp() {\n    parent::setUp('restful_example');\n\n    // Allow anonymous users to edit articles.\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('edit any article content' => TRUE));\n  }\n\n  /**\n   * Test viewing an entity (GET method).\n   */\n  public function testViewEntity() {\n    $user1 = $this->drupalCreateUser(array('edit own article content'));\n\n    $title = $this->randomName();\n    $settings = array(\n      'type' => 'article',\n      'title' => $title,\n      'uid' => $user1->uid,\n    );\n    $node1 = $this->drupalCreateNode($settings);\n\n    // Test version 1.0\n    $result = $this->httpRequest('api/v1.0/articles/' . $node1->nid);\n    $expected_result = array(\n      'data' => array(array(\n        'id' => $node1->nid,\n        'label' => $node1->title,\n        'self' => url('api/v1.0/articles/' . $node1->nid, array('absolute' => TRUE)),\n      )),\n      'self' => array(\n        'title' => 'Self',\n        'href' => url('api/v1.0/articles/' . $node1->nid, array('absolute' => TRUE)),\n      ),\n    );\n\n    $this->assertEqual($result['body'], json_encode($expected_result));\n\n    // Test version 1.1\n    $result = $this->httpRequest('api/v1.1/articles/' . $node1->nid, RequestInterface::METHOD_GET);\n    $expected_result['self']['href'] = url('api/v1.1/articles/' . $node1->nid, array('absolute' => TRUE));\n    unset($expected_result['data'][0]['self']);\n    $this->assertEqual($result['body'], json_encode($expected_result));\n\n    // Test method override.\n    $headers = array(\n      'X-HTTP-Method-Override' => RequestInterface::METHOD_PATCH,\n      'X-CSRF-Token' => drupal_get_token(\\Drupal\\restful\\Plugin\\authentication\\Authentication::TOKEN_VALUE),\n      'Content-Type' => 'application/json',\n      'Authorization' => 'Basic ' . base64_encode($user1->name . ':' . $user1->pass_raw),\n    );\n    $body = array(\n      'label' => 'new title',\n    );\n    $handler = restful()->getResourceManager()->getPlugin('articles:1.1');\n    $header_bag = new \\Drupal\\restful\\Http\\HttpHeaderBag($headers);\n    $handler->setRequest(Request::create('api/v1.0/articles/' . $node1->nid, array(), RequestInterface::METHOD_POST, $header_bag, FALSE, NULL, array(), array(), array(), $body));\n    $handler->setPath($node1->nid);\n    restful()->getFormatterManager()->format($handler->process(), 'json');\n\n    $node1 = node_load($node1->nid);\n    $this->assertEqual($node1->title, 'new title', 'HTTP method was overridden.');\n  }\n\n  /**\n   * Test HTTP headers change according to the response.\n   */\n  public function testHttpHeadersAndStatus() {\n    // Valid request (even though it's empty).\n    $result = $this->httpRequest('api/v1.0/articles/', RequestInterface::METHOD_GET);\n    $this->assertTrue(strpos($result['headers'], 'application/json;'), '\"application/json\" found in valid request.');\n\n    // Invalid request.\n    $result = $this->httpRequest('api/v1.0/articles/invalid_id', RequestInterface::METHOD_GET);\n    $this->assertTrue(strpos($result['headers'], 'application/problem+json;') !== FALSE, '\"application/problem+json\" found in invalid request.');\n    // Switch site to offline mode.\n    variable_set('maintenance_mode', TRUE);\n    $this->httpauth_credentials = NULL;\n    $result = $this->httpRequest('api/login');\n    $this->assertEqual($result['code'], '503', '503 status code sent for site in offline mode.');\n  }\n\n  /**\n   * Test hijacking of api/* pages and showing proper error messages.\n   */\n  public function testNotFoundDelivery() {\n    // Invalid URLs.\n    $urls = array(\n      'api/invalid',\n    );\n\n    foreach ($urls as $url) {\n      $result = $this->httpRequest($url);\n\n      $body = drupal_json_decode($result['body']);\n      $this->assertEqual($result['code'], '404', format_string('404 status code sent for @url url.', array('@url' => $url)));\n      $this->assertTrue(strpos($result['headers'], 'application/problem+json;') !== FALSE, '\"application/problem+json\" found in invalid request.');\n      $this->assertEqual($body['title'], 'Invalid URL path.', 'Correct error message.');\n    }\n\n    // Non-related url.\n    $result = $this->httpRequest('api-api');\n    $this->assertEqual($result['code'], '404', format_string('404 status code sent for @url url.', array('@url' => $url)));\n    $this->assertFalse(strpos($result['headers'], 'application/problem+json;'), 'Only correct URL is hijacked.');\n  }\n\n  /**\n   * Test the version negotiation.\n   */\n  public function testVersionNegotiation() {\n    // Fake the HTTP header.\n    $test_harness = array(\n      array(\n        'path' => 'api/v1.1/articles',\n        'version_header' => NULL,\n        'expected_version' => array(1, 1),\n        'expected_resource' => 'articles',\n      ),\n      array(\n        'path' => 'api/v1/articles',\n        'version_header' => NULL,\n        'expected_version' => array(1, 7),\n        'expected_resource' => 'articles',\n      ),\n      array(\n        'path' => 'api/articles',\n        'version_header' => 'v1',\n        'expected_version' => array(1, 7),\n        'expected_resource' => 'articles',\n      ),\n      array(\n        'path' => 'api/articles',\n        'version_header' => 'v1.0',\n        'expected_version' => array(1, 0),\n        'expected_resource' => 'articles',\n      ),\n      array(\n        'path' => 'api/articles',\n        'version_header' => NULL,\n        'expected_version' => array(2, 1),\n        'expected_resource' => 'articles',\n      ),\n    );\n\n    foreach ($test_harness as $test_item) {\n      $headers = NULL;\n      if (!empty($test_item['version_header'])) {\n        $headers = new \\Drupal\\restful\\Http\\HttpHeaderBag(array(\n          'X-API-Version' => $test_item['version_header'],\n        ));\n      }\n      $request = \\Drupal\\restful\\Http\\Request::create($test_item['path'], array(), RequestInterface::METHOD_GET, $headers);\n      $resource_manager = new \\Drupal\\restful\\Resource\\ResourceManager($request);\n      drupal_static_reset('Drupal\\restful\\Resource\\ResourceManager::getVersionFromRequest');\n      $this->assertEqual($resource_manager->getVersionFromRequest(), $test_item['expected_version'], sprintf('%s resolves correctly.', $test_item['path']));\n      $this->assertEqual($resource_manager->getResourceIdFromRequest(), $test_item['expected_resource'], sprintf('Resource name obtained correctly from %s.', $test_item['path']));\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulJsonApiTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains \\RestfulJsonApiTestCase.\n */\n\nuse Drupal\\restful\\Http\\Request;\n\n/**\n * Class RestfulJsonApiTestCase.\n */\nclass RestfulJsonApiTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * Hold the RESTful handler.\n   *\n   * @var \\Drupal\\restful\\Plugin\\resource\\ResourceInterface\n   */\n  protected $handler = NULL;\n\n  /**\n   * Account created for testing.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * Array of entities.\n   *\n   * @var \\Entity[]\n   */\n  protected $entities = array();\n\n  /**\n   * JSON API formatter.\n   *\n   * @var \\Drupal\\restful\\Plugin\\formatter\\FormatterInterface\n   */\n  protected $formatter;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'JSON API',\n      'description' => 'Test the JSON API formatter.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_test', 'entityreference', 'uuid');\n\n    restful_test_add_fields();\n\n    $this->account = $this->drupalCreateUser();\n    $this->entities = $this->createEntities();\n    $this->handler = restful()->getResourceManager()->getPlugin('main:1.1');\n    $this->formatter = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL, 'json_api');\n    $configuration = array(\n      'resource' => $this->handler,\n    );\n    $this->formatter->setConfiguration($configuration);\n  }\n\n  /**\n   * Create test entities.\n   *\n   * @return Entity[]\n   *   An array of entities.\n   */\n  protected function createEntities() {\n    $entities = array();\n    $entities[] = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $this->account->uid,\n    ));\n    $entities[0]->save();\n\n    $entities[] = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $this->account->uid,\n    ));\n    $entities[1]->save();\n\n    $entities[] = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $this->account->uid,\n    ));\n\n    $entities[0]->entity_reference_single[LANGUAGE_NONE][] = array('target_id' => $entities[1]->pid);\n    $entities[0]->save();\n    $entities[2]->entity_reference_single[LANGUAGE_NONE][] = array('target_id' => $entities[0]->pid);\n    $entities[2]->entity_reference_multiple[LANGUAGE_NONE][] = array('target_id' => $entities[0]->pid);\n    $entities[2]->entity_reference_multiple[LANGUAGE_NONE][] = array('target_id' => $entities[1]->pid);\n    $entities[2]->save();\n\n    return $entities;\n  }\n\n  /**\n   * Test requesting resources.\n   */\n  public function testReading() {\n    /* @var \\EntityDrupalWrapper $wrapper */\n    $wrapper = entity_metadata_wrapper('entity_test', $this->entities[2]);\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier()));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    // Assert the basic properties of the resource.\n    $this->assertEqual('main', $result['data']['type']);\n    $this->assertEqual($wrapper->getIdentifier(), $result['data']['id']);\n\n    // 1. Assert the \"attributes\" key.\n    // Remove the NULL keys since we're not adding them to the $expected array.\n    $attributes = array_filter($result['data']['attributes']);\n    $expected = array(\n      // The following fields don't have a resource in their definition,\n      // therefore they are treated as regular fields and not relationships.\n      'entity_reference_multiple' => array(\n        $this->entities[0]->pid,\n        $this->entities[1]->pid,\n      ),\n      'entity_reference_single' => $this->entities[0]->pid,\n      'id' => $wrapper->getIdentifier(),\n      'label' => $wrapper->label(),\n      'self' => $this->handler->versionedUrl($wrapper->getIdentifier()),\n      // Create it empty and fill it later.\n      'text_multiple' => array(),\n      'text_single' => $wrapper->text_single->value(),\n    );\n    foreach ($wrapper->text_multiple as $text_multiple_wrapper) {\n      /* @var \\EntityStructureWrapper $text_multiple_wrapper */\n      $expected['text_multiple'][] = $text_multiple_wrapper->value();\n    }\n    $this->assertEqual(array_filter($expected), array_filter($attributes));\n    $this->assertEqual($this->handler->versionedUrl($wrapper->getIdentifier(), array(\n      'query' => array('page' => array('number' => 1)),\n    )), $result['links']['self']);\n\n    // 2. Assert the relationships.\n    $relationships = $result['data']['relationships'];\n    // Make sure that the entity_reference_*_resource are included as\n    // relationships.\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['links'], array(\n      'self' => $this->handler->versionedUrl($wrapper->getIdentifier() . '/relationships/entity_reference_multiple_resource'),\n      'related' => $this->handler->versionedUrl('', array('query' => array('filter' => array('entity_reference_multiple_resource' => $wrapper->entity_reference_multiple[0]->getIdentifier())))),\n    ));\n    $this->assertEqual($relationships['entity_reference_single_resource']['data']['type'], 'main');\n    $this->assertEqual($relationships['entity_reference_single_resource']['data']['id'], $wrapper->entity_reference_single->getIdentifier());\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][0]['type'], 'main');\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][0]['id'], $wrapper->entity_reference_multiple[0]->getIdentifier());\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][1]['type'], 'main');\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][1]['id'], $wrapper->entity_reference_multiple[1]->getIdentifier());\n\n    // Make sure that using fields + includes lists all the fields in the\n    // embedded entity if there is no subfield added.\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier(), array(\n      'include' => 'entity_reference_multiple_resource,entity_reference_single_resource',\n      'fields' => 'entity_reference_multiple_resource,entity_reference_single_resource',\n    )));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $this->assertEqual(count($result['included'][0]['attributes']), 16);\n\n    // Now make sure that including fields only lists those fields.\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier(), array(\n      'include' => 'entity_reference_single_resource',\n      'fields' => 'entity_reference_single_resource.label',\n    )));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $this->assertEqual(count($result['included'][0]['attributes']), 1);\n\n    // Make a request with the include query string.\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier(), array('include' => 'entity_reference_multiple_resource,entity_reference_single_resource')));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $included = $result['included'];\n    // Make sure there are no repeated includes.\n    $this->assertEqual(2, count($included));\n    $expected_includes = array(\n      array(\n        'attributes' => array(\n          'entity_reference_single' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n          'id' => $wrapper->entity_reference_multiple[0]->getIdentifier(),\n          'label' => $wrapper->entity_reference_multiple[0]->label(),\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[0]->getIdentifier()),\n        ),\n        'id' => $wrapper->entity_reference_multiple[0]->getIdentifier(),\n        'links' => array(\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[0]->getIdentifier()),\n        ),\n        'type' => 'main',\n        'relationships' => array(\n          'entity_reference_single_resource' => array(\n            'data' => array(\n              'id' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n              'type' => 'main',\n            ),\n            'links' => array(\n              'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[0]->getIdentifier() . '/relationships/entity_reference_single_resource'),\n              'related' => $this->handler->versionedUrl('', array('query' => array('filter' => array('entity_reference_single_resource' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier())))),\n            ),\n          ),\n        ),\n      ),\n      array(\n        'attributes' => array(\n          'id' => $wrapper->entity_reference_multiple[1]->getIdentifier(),\n          'label' => $wrapper->entity_reference_multiple[1]->label(),\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[1]->getIdentifier()),\n        ),\n        'id' => $wrapper->entity_reference_multiple[1]->getIdentifier(),\n        'links' => array(\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[1]->getIdentifier()),\n        ),\n        'type' => 'main',\n      ),\n    );\n    // Remove the empty fields from the actual response for easier comparison.\n    $included[0]['attributes'] = array_filter($included[0]['attributes']);\n    $included[1]['attributes'] = array_filter($included[1]['attributes']);\n    $this->assertEqual($expected_includes, $included);\n\n    // 3. Assert the nested relationships.\n    $relationships = $result['data']['relationships'];\n    // Make sure that the entity_reference_*_resource are included as\n    // relationships.\n    $this->assertEqual($relationships['entity_reference_single_resource']['data']['type'], 'main');\n    $this->assertEqual($relationships['entity_reference_single_resource']['data']['id'], $wrapper->entity_reference_single->getIdentifier());\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][0]['type'], 'main');\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][0]['id'], $wrapper->entity_reference_multiple[0]->getIdentifier());\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][1]['type'], 'main');\n    $this->assertEqual($relationships['entity_reference_multiple_resource']['data'][1]['id'], $wrapper->entity_reference_multiple[1]->getIdentifier());\n\n    // Make a request with the include query string.\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier(), array('include' => 'entity_reference_single_resource.entity_reference_single_resource')));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $included = $result['included'];\n    // Make sure there are no repeated includes.\n    $this->assertEqual(2, count($included));\n    $expected_includes = array(\n      array(\n        'attributes' => array(\n          'entity_reference_single' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n          'id' => $wrapper->entity_reference_multiple[0]->getIdentifier(),\n          'label' => $wrapper->entity_reference_multiple[0]->label(),\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[0]->getIdentifier()),\n        ),\n        'id' => $wrapper->entity_reference_multiple[0]->getIdentifier(),\n        'links' => array(\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[0]->getIdentifier()),\n        ),\n        'type' => 'main',\n        'relationships' => array(\n          'entity_reference_single_resource' => array(\n            'data' => array(\n              'id' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n              'type' => 'main',\n            ),\n            'links' => array(\n              'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[0]->getIdentifier() . '/relationships/entity_reference_single_resource'),\n              'related' => $this->handler->versionedUrl('', array('query' => array('filter' => array('entity_reference_single_resource' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier())))),\n            ),\n          ),\n        ),\n      ),\n      array(\n        'attributes' => array(\n          'id' => $wrapper->entity_reference_multiple[1]->getIdentifier(),\n          'label' => $wrapper->entity_reference_multiple[1]->label(),\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[1]->getIdentifier()),\n        ),\n        'id' => $wrapper->entity_reference_multiple[1]->getIdentifier(),\n        'links' => array(\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_multiple[1]->getIdentifier()),\n        ),\n        'type' => 'main',\n      ),\n    );\n    // Remove the empty fields from the actual response for easier comparison.\n    $included[0]['attributes'] = array_filter($included[0]['attributes']);\n    $included[1]['attributes'] = array_filter($included[1]['attributes']);\n    sort($expected_includes);\n    sort($included);\n    $this->assertEqual($expected_includes, $included);\n\n    // 4. Assert the nested sparse fieldsets.\n    // Make a request with the include query string.\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier(), array(\n      'include' => 'entity_reference_single_resource.entity_reference_single_resource',\n      'fields' => implode(',', array(\n        // Request a field in the first include and another one in the second.\n        'entity_reference_single_resource.text_single',\n        'entity_reference_single_resource.entity_reference_single_resource.text_multiple',\n      )),\n    )));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $this->formatter->setResource($this->handler);\n    $result = $this->formatter->prepare($this->handler->process());\n\n    $this->assertEqual(2, count($result['included']));\n    // Make sure there is only one field in the nested includes.\n    $this->assertTrue(empty($result['data']['attributes']));\n    $this->assertFalse(empty($result['data']['relationships']));\n    $this->assertEqual(array('text_single'), array_keys($result['included'][0]['attributes']));\n    $this->assertFalse(empty($result['included'][0]['relationships']));\n    $this->assertEqual(array('text_multiple'), array_keys($result['included'][1]['attributes']));\n    $this->assertTrue(empty($result['included'][1]['relationships']));\n\n    // Make a request with the include query string.\n    $this->handler->setRequest(Request::create('api/v1.1/main/' . $wrapper->getIdentifier(), array(\n      'include' => 'entity_reference_single_resource.entity_reference_single_resource',\n      'fields' => implode(',', array(\n        // Request a field in the first include and another one in the second.\n        'entity_reference_single_resource.entity_reference_single_resource.text_multiple',\n      )),\n    )));\n    $this->handler->setPath($wrapper->getIdentifier());\n    $this->formatter->setResource($this->handler);\n    $result = $this->formatter->prepare($this->handler->process());\n\n    $this->assertEqual(2, count($result['included']));\n    // Make sure there is only one field in the nested includes.\n    $this->assertTrue(empty($result['data']['attributes']));\n    $this->assertFalse(empty($result['data']['relationships']));\n    $this->assertTrue(empty($result['included'][0]['attributes']));\n    $this->assertFalse(empty($result['included'][0]['relationships']));\n    $this->assertTrue(empty($result['included'][1]['relationships']));\n    $this->assertEqual(array('text_multiple'), array_keys($result['included'][1]['attributes']));\n\n    // 6. Assert the attributes for a list.\n    // Make a list request and check the attributes.\n    $this->handler->setRequest(Request::create(''));\n    $this->handler->setPath('');\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $this->assertTrue(\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase::isArrayNumeric($result['data']));\n    $this->assertTrue(count($result['data']), count($this->entities));\n    foreach ($result['data'] as $delta => $row) {\n      // Assert the basic properties of the resource.\n      $this->assertEqual('main', $row['type']);\n      $this->assertEqual($this->entities[$delta]->pid, $row['id']);\n    }\n\n    $expected = array_filter($expected);\n    $attributes = array_filter($result['data'][2]['attributes']);\n    $this->assertEqual($expected, $attributes);\n\n    // 5. Assert the relationships for a list.\n    $this->handler->setRequest(Request::create('', array('include' => 'entity_reference_single_resource')));\n    $this->handler->setPath('');\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $included = $result['included'];\n    $this->assertEqual(2, count($included));\n    $expected_includes = array(\n      array(\n        'type' => 'main',\n        'id' => (string) $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n        'links' => array(\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_single->entity_reference_single->getIdentifier()),\n        ),\n        'attributes' => array(\n          'id' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n          'label' => $wrapper->entity_reference_single->entity_reference_single->label(),\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_single->entity_reference_single->getIdentifier()),\n        ),\n      ),\n      array(\n        'type' => 'main',\n        'id' => (string) $wrapper->entity_reference_single->getIdentifier(),\n        'links' => array(\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_single->getIdentifier()),\n        ),\n        'attributes' => array(\n          'entity_reference_single' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n          'id' => $wrapper->entity_reference_single->getIdentifier(),\n          'label' => $wrapper->entity_reference_single->label(),\n          'self' => $this->handler->versionedUrl($wrapper->entity_reference_single->getIdentifier()),\n        ),\n        'relationships' => array(\n          'entity_reference_single_resource' => array(\n            'data' => array(\n              'id' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier(),\n              'type' => 'main',\n            ),\n            'links' => array(\n              'self' => $this->handler->versionedUrl($wrapper->entity_reference_single->getIdentifier() . '/relationships/entity_reference_single_resource'),\n              'related' => $this->handler->versionedUrl('', array('query' => array('filter' => array('entity_reference_single_resource' => $wrapper->entity_reference_single->entity_reference_single->getIdentifier())))),\n            ),\n          ),\n        ),\n      ),\n    );\n    // Remove the empty fields from the actual response for easier comparison.\n    $included[0]['attributes'] = array_filter($included[0]['attributes']);\n    $included[1]['attributes'] = array_filter($included[1]['attributes']);\n    $this->assertEqual($expected_includes, $included);\n\n    // 7. Assert request processing.\n    $request = Request::create('', array(\n      'fields' => 'first.second.third.fourth,first.third.fourth',\n      'include' => 'fifth.sixth.seventh',\n    ));\n    $input = $request->getParsedInput();\n    $this->assertEqual($input['fields'], 'first,first.second,first.second.third,first.second.third.fourth,first.third,first.third.fourth');\n    $this->assertEqual($input['include'], 'fifth,fifth.sixth,fifth.sixth.seventh');\n\n    // 8. Assert generic reference resource field.\n    // Add some data to the DB table.\n    $record = array(\n      'str_field' => $this->randomName(),\n      'int_field' => mt_rand(1, 10),\n      'serialized_field' => serialize(array()),\n    );\n    drupal_write_record('restful_test_db_query', $record);\n    $handler = restful()->getResourceManager()->getPlugin('main:1.8');\n    $handler->setRequest(Request::create('', array(\n      'include' => 'random_rel',\n      'range' => 1,\n    )));\n    $handler->setPath(1);\n    $formatter = restful()->getFormatterManager()->getPlugin('json_api');\n    $formatter->setResource($handler);\n    $result = $formatter->prepare($handler->process());\n    $this->assertEqual($result['included'][0]['attributes']['id'], 1);\n  }\n\n  /**\n   * Test pagination.\n   */\n  public function testPagination() {\n    $entities = $this->createEntities();\n    $count = count($entities);\n    for ($index = 0; $index < 3; $index++) {\n      $entities[] = entity_create('entity_test', array(\n        'name' => 'main',\n        'uid' => $this->account->uid,\n      ));\n      $entities[$count + $index]->save();\n    }\n\n    // 1. Test pagination links in the first page.\n    $range = 2;\n    $this->handler->setRequest(Request::create('', array('range' => $range)));\n    $this->handler->setPath('');\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $links = $result['links'];\n    $expected_links = array(\n      'self' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 1,\n            'size' => $range,\n          ),\n        ),\n      )),\n      'first' => $this->handler->versionedUrl('', array('query' => array('page' => array('size' => $range)))),\n      'last' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 5,\n            'size' => $range,\n          ),\n        ),\n      )),\n      'next' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 2,\n            'size' => $range,\n          ),\n        ),\n      )),\n    );\n    $this->assertEqual($links, $expected_links);\n\n    // 2. Test pagination links in the middle page.\n    $range = 2;\n    $this->handler->setRequest(Request::create('', array(\n      'range' => $range,\n      'page' => 2,\n    )));\n    $this->handler->setPath('');\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $links = $result['links'];\n    $expected_links = array(\n      'self' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 2,\n            'size' => $range,\n          ),\n        ),\n      )),\n      'first' => $this->handler->versionedUrl('', array('query' => array('page' => array('size' => $range)))),\n      'previous' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 1,\n            'size' => $range,\n          ),\n        ),\n      )),\n      'last' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 5,\n            'size' => $range,\n          ),\n        ),\n      )),\n      'next' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'number' => 3,\n            'size' => $range,\n          ),\n        ),\n      )),\n    );\n    $this->assertEqual($links, $expected_links);\n\n    // 3. Test pagination links in the last page.\n    $range = 2;\n    $this->handler->setRequest(Request::create('', array(\n      'page' => array(\n        'size' => $range,\n        'number' => 5,\n      ),\n    )));\n    $this->handler->setPath('');\n    $this->formatter->setResource($this->handler);\n    $resource_field_collections = $this->handler->process();\n    $result = drupal_json_decode($this->formatter->format($resource_field_collections));\n    $links = $result['links'];\n    $expected_links = array(\n      'self' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'size' => $range,\n            'number' => 5,\n          ),\n        ),\n      )),\n      'first' => $this->handler->versionedUrl('', array('query' => array('page' => array('size' => $range)))),\n      'previous' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'size' => $range,\n            'number' => 4,\n          ),\n        ),\n      )),\n      'last' => $this->handler->versionedUrl('', array(\n        'query' => array(\n          'page' => array(\n            'size' => $range,\n            'number' => 5,\n          ),\n        ),\n      )),\n    );\n    $this->assertEqual($links, $expected_links);\n  }\n\n  /**\n   * Test alternative ID field.\n   */\n  public function testAlternativeIdField() {\n    $entities = $this->createEntities();\n    $resource_manager = restful()->getResourceManager();\n    $format_manager = restful()->getFormatterManager();\n    $formatter = $format_manager->negotiateFormatter(NULL, 'json_api');\n    $resource_manager->clearPluginCache('main:1.7');\n    $handler = $resource_manager->getPlugin('main:1.7');\n\n    // Add files and taxonomy term references.\n    $query = new EntityFieldQuery();\n    $result = $query->entityCondition('entity_type', 'taxonomy_term')\n      ->entityCondition('bundle', 'test_vocab')\n      ->execute();\n    $tids = array_keys($result['taxonomy_term']);\n\n    $images = array();\n    foreach ($this->drupalGetTestFiles('image') as $file) {\n      $file = file_save($file);\n      $images[] = $file->fid;\n    }\n\n    $entities[2]->term_single[LANGUAGE_NONE][] = array('tid' => $tids[0]);\n    $entities[2]->term_multiple[LANGUAGE_NONE][] = array('tid' => $tids[1]);\n    $entities[2]->term_multiple[LANGUAGE_NONE][] = array('tid' => $tids[2]);\n    $entities[2]->file_single[LANGUAGE_NONE][] = array(\n      'fid' => $images[0],\n      'display' => TRUE,\n    );\n    $entities[2]->file_multiple[LANGUAGE_NONE][] = array(\n      'fid' => $images[1],\n      'display' => TRUE,\n    );\n    $entities[2]->file_multiple[LANGUAGE_NONE][] = array(\n      'fid' => $images[2],\n      'display' => TRUE,\n    );\n    entity_save('entity_test', $entities[2]);\n\n\n    $handler->setRequest(Request::create('api/main/v1.7/' . $entities[2]->uuid));\n    $handler->setPath($entities[2]->uuid);\n    $formatter->setResource($handler);\n    $response = $formatter->prepare($handler->process());\n\n    $result = $response['data']['attributes'];\n\n    // Make sure that IDs are UUID.\n    $this->assertEqual(count(entity_uuid_load('file', array($result['file_single']))), 1, 'UUID correctly loaded for: file_single');\n    $this->assertEqual(count(entity_uuid_load('file', $result['file_multiple'])), 2, 'UUID correctly loaded for: file_multiple');\n    $this->assertEqual(count(entity_uuid_load('taxonomy_term', array($result['term_single']))), 1, 'UUID correctly loaded for: term_single');\n    $this->assertEqual(count(entity_uuid_load('taxonomy_term', $result['term_multiple'])), 2, 'UUID correctly loaded for: term_multiple');\n    $this->assertEqual(count(entity_uuid_load('entity_test', array($result['entity_reference_single']))), 1, 'UUID correctly loaded for: entity_reference_single');\n    $this->assertEqual(count(entity_uuid_load('entity_test', $result['entity_reference_multiple'])), 2, 'UUID correctly loaded for: entity_reference_multiple');\n\n    // Assert relationship.\n    $relationships = $response['data']['relationships'];\n    $this->assertEqual($relationships['entity_reference_resource']['data']['id'], $entities[0]->uuid);\n    $this->assertEqual($relationships['entity_reference_resource']['data']['type'], 'main');\n\n    // Assert that the self link contains the UUID.\n    $this->assertTrue(strpos($response['links']['self'], $entities[2]->uuid) !== FALSE, 'UUID found in self link.');\n\n    // Test that if referencedIdProperty and idField don't match, embedding does\n    // not happen.\n    variable_set('restful_test_alternative_id_error', TRUE);\n    $resource_manager->clearPluginCache('main:1.7');\n    $handler = $resource_manager->getPlugin('main:1.7');\n    $handler->setRequest(Request::create('api/main/v1.7/' . $entities[2]->uuid, array(\n      'include' => 'entity_reference_resource_error',\n    )));\n    $handler->setPath($entities[2]->uuid);\n    $format_manager->setResource($handler);\n    $response = $format_manager->negotiateFormatter(NULL, 'json_api')\n      ->prepare($handler->process());\n\n    $result = $response['data']['attributes'];\n    // Make sure the entity_reference_resource_error is NULL.\n    $this->assertNull($result['entity_reference_resource_error'], 'Entity cannot be loaded with uuid when there is no idField.');\n    variable_del('restful_test_alternative_id_error');\n\n    // Clear caches to remove error field.\n    $resource_manager->clearPluginCache('main:1.7');\n    $handler = $resource_manager->getPlugin('main:1.7');\n\n    // Filter the entities by the reference.\n    $handler->setRequest(Request::create('api/main/v1.7', array(\n      'filter' => array('entity_reference_single' => $entities[0]->uuid),\n    )));\n    $handler->setPath('');\n    $formatter->setResource($handler);\n    $response = $formatter->prepare($handler->process());\n    // Assert that $entities[2] points to $entities[0]\n    $this->assertEqual($response['data'][0]['id'], $entities[2]->uuid);\n    // Filter the entities by the reference.\n    $handler->setRequest(Request::create('api/main/v1.7', array(\n      'filter' => array('entity_reference_multiple' => $entities[1]->uuid),\n    )));\n    $handler->setPath('');\n    $formatter->setResource($handler);\n    $response = $formatter->prepare($handler->process());\n    // Assert that $entities[2] points to $entities[0]\n    $this->assertEqual($response['data'][0]['id'], $entities[2]->uuid);\n  }\n\n  /**\n   * Sub-request parsing.\n   */\n  public function testSubRequestParsing() {\n    $relationships = array(\n      'rel1' => array('data' => array('type' => 'tags', 'id' => 7)),\n      'rel2' => array(\n        'data' => array(\n          array(\n            'type' => 'articles',\n            'id' => 1,\n          ),\n          array(\n            'type' => 'articles',\n            'id' => 2,\n            'meta' => array('subrequest' => array('method' => 'PUT')),\n          ),\n          array(\n            'type' => 'articles',\n            'id' => 3,\n            'meta' => array('subrequest' => array('method' => 'PATCH')),\n          ),\n          array(\n            'type' => 'articles',\n            'id' => 'newRel2--1',\n            'meta' => array(\n              'subrequest' => array(\n                'method' => 'POST',\n                'headers' => array('X-CSRF-Token' => 'my-token'),\n              ),\n            ),\n          ),\n        ),\n      ),\n    );\n\n    // Generate 3 random strings.\n    $rnd_text = array_map(array($this, 'randomName'), range(0, 4));\n    $included = array(\n      array(\n        'type' => 'articles',\n        'id' => 1,\n        'attributes' => array('label' => $rnd_text[0]),\n        'relationships' => array(\n          'articles' => array(\n            'data' => array(\n              'type' => 'articles',\n              'id' => 2,\n            ),\n          ),\n        ),\n      ),\n      array(\n        'type' => 'articles',\n        'id' => 2,\n        'attributes' => array('label' => $rnd_text[1]),\n      ),\n      array(\n        'type' => 'articles',\n        'id' => 3,\n        'attributes' => array('label' => $rnd_text[2]),\n      ),\n      array(\n        'type' => 'articles',\n        'id' => 'newRel2--1',\n        'attributes' => array('label' => $rnd_text[3]),\n        'relationships' => array(\n          'articles' => array(\n            'data' => array(\n              'type' => 'articles',\n              'id' => 1,\n            ),\n          ),\n        ),\n      ),\n    );\n    $data = array(\n      array(\n        'type' => 'articles',\n        'id' => 5,\n        'attributes' => array(\n          'title' => $rnd_text[4],\n        ),\n        'relationships' => $relationships,\n      ),\n    );\n    $json_api = array(\n      'data' => $data,\n      'included' => $included,\n    );\n    $parsed_body = restful()\n      ->getFormatterManager()\n      ->getPlugin('json_api')\n      ->parseBody(drupal_json_encode($json_api));\n\n    $expected = array(\n      array(\n        'title' => $rnd_text[4],\n        'rel1' => array('id' => 7),\n        'rel2' => array(\n          array('id' => 1),\n          array(\n            'id' => 2,\n            'body' => array(\n              'label' => $rnd_text[1],\n            ),\n            'request' => array('method' => 'PUT'),\n          ),\n          array(\n            'id' => 3,\n            'body' => array(\n              'label' => $rnd_text[2],\n            ),\n            'request' => array('method' => 'PATCH'),\n          ),\n          array(\n            'body' => array(\n              'label' => $rnd_text[3],\n              'articles' => array('id' => 1),\n            ),\n            'request' => array(\n              'method' => 'POST',\n              'headers' => array('X-CSRF-Token' => 'my-token'),\n            ),\n          ),\n        ),\n      ),\n    );\n\n    $this->assertEqual($expected, $parsed_body);\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulListEntityMultipleBundlesTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulListEntityMultipleBundlesTestCase\n */\n\nclass RestfulListEntityMultipleBundlesTestCase extends DrupalWebTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'List entity with multiple bundles',\n      'description' => 'Test listing an entity with multiple bundles.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test listing an entity with multiple bundles.\n   */\n  public function testList() {\n    $user1 = $this->drupalCreateUser();\n    /* @var \\Entity $entity1 */\n    $entity1 = entity_create('entity_test', array('name' => 'main', 'uid' => $user1->uid));\n    $entity1->save();\n\n    $entity2 = entity_create('entity_test', array('name' => 'main', 'uid' => $user1->uid));\n    /* @var \\Entity $entity2 */\n    $entity2->save();\n\n    $entity3 = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));\n    /* @var \\Entity $entity3 */\n    $entity3->save();\n\n    $handler = restful()->getResourceManager()->getPlugin('entity_tests:1.0');\n    $formatter = restful()->getFormatterManager()->getPlugin('json');\n    $formatter->setResource($handler);\n\n    $expected_result = array(\n      array(\n        'id' => $entity1->pid,\n        'label' => 'Main test type',\n        'self' => url('api/v1.0/entity_tests/' . $entity1->pid, array('absolute' => TRUE)),\n        'main_bundle' => array(\n          'id' => $entity1->pid,\n          'label' => 'Main test type',\n          'self' => url('api/v1.0/main/' . $entity1->pid, array('absolute' => TRUE)),\n        ),\n        'tests_bundle' => NULL,\n      ),\n      array(\n        'id' => $entity2->pid,\n        'label' => 'Main test type',\n        'self' => url('api/v1.0/entity_tests/' . $entity2->pid, array('absolute' => TRUE)),\n        'main_bundle' => array(\n          'id' => $entity2->pid,\n          'label' => 'Main test type',\n          'self' => url('api/v1.0/main/' . $entity2->pid, array('absolute' => TRUE)),\n        ),\n        'tests_bundle' => NULL,\n      ),\n      array(\n        'id' => $entity3->pid,\n        'label' => 'label',\n        'self' => url('api/v1.0/entity_tests/' . $entity3->pid, array('absolute' => TRUE)),\n        'main_bundle' => NULL,\n        'tests_bundle' => array(\n          'type' => 'test',\n          'id' => $entity3->pid,\n          'label' => 'label',\n          'self' => url('api/v1.0/tests/' . $entity3->pid, array('absolute' => TRUE)),\n        ),\n      ),\n    );\n    $result = $formatter->prepare($handler->doGet());\n    $this->assertEqual($result['data'], $expected_result);\n  }\n}\n"
  },
  {
    "path": "tests/RestfulListTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulListTestCase.\n */\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Exception\\UnprocessableEntityException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\n/**\n * Class RestfulListTestCase.\n */\nclass RestfulListTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'List entities',\n      'description' => 'Test the listing of entities.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_test');\n  }\n\n  /**\n   * Test the sorting of entities.\n   */\n  public function testSort() {\n    // Allow the anonymous users access to the author field.\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles' => TRUE));\n\n    $user1 = $this->drupalCreateUser();\n    $user2 = $this->drupalCreateUser();\n\n    $settings = array('type' => 'article');\n\n    $info = array(\n      'abc' => $user1->uid,\n      'xyz' => $user1->uid,\n      'efg' => $user2->uid,\n    );\n    $nodes = array();\n    foreach ($info as $title => $uid) {\n      $settings['title'] = $title;\n      $settings['uid'] = $uid;\n      $node = $this->drupalCreateNode($settings);\n      $nodes[$title] = $node->nid;\n    }\n\n    // Add unpublished node, to confirm it is not listed.\n    $settings['status'] = NODE_NOT_PUBLISHED;\n    $this->drupalCreateNode($settings);\n\n    $resource_manager = restful()->getResourceManager();\n\n    $handler = $resource_manager->getPlugin('articles:1.0');\n    $query['fields'] = 'id,label';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n\n    // No sorting (default sorting).\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $nodes['abc'],\n        'label' => 'abc',\n      ),\n      array(\n        'id' => $nodes['xyz'],\n        'label' => 'xyz',\n      ),\n      array(\n        'id' => $nodes['efg'],\n        'label' => 'efg',\n      ),\n    );\n    $this->assertEqual($result, $expected_result, 'No sorting (default sorting).');\n\n    // Sort by ID descending.\n    $query['sort'] = '-id';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $nodes['efg'],\n        'label' => 'efg',\n      ),\n      array(\n        'id' => $nodes['xyz'],\n        'label' => 'xyz',\n      ),\n      array(\n        'id' => $nodes['abc'],\n        'label' => 'abc',\n      ),\n    );\n    $this->assertEqual($result, $expected_result, 'Sort by ID descending.');\n\n    // Sort by label ascending.\n    $query['sort'] = 'label';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $nodes['abc'],\n        'label' => 'abc',\n      ),\n      array(\n        'id' => $nodes['efg'],\n        'label' => 'efg',\n      ),\n      array(\n        'id' => $nodes['xyz'],\n        'label' => 'xyz',\n      ),\n    );\n    $this->assertEqual($result, $expected_result, 'Sort by label ascending.');\n\n    // Sort by label and by ID. For that we add another node titled \"abc\".\n    $settings = array(\n      'type' => 'article',\n      'title' => 'abc',\n    );\n    $node = $this->drupalCreateNode($settings);\n\n    $query['sort'] = 'label,id';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $nodes['abc'],\n        'label' => 'abc',\n      ),\n      array(\n        'id' => $node->nid,\n        'label' => 'abc',\n      ),\n      array(\n        'id' => $nodes['efg'],\n        'label' => 'efg',\n      ),\n      array(\n        'id' => $nodes['xyz'],\n        'label' => 'xyz',\n      ),\n    );\n    $this->assertEqual($result, $expected_result, 'Sort by ID and by label.');\n\n    // Test default sorting from plugin definition; by label, then by reverse\n    // id.\n    $handler = $resource_manager->getPlugin('test_articles:1.1');\n    unset($query['sort']);\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $node->nid,\n        'label' => 'abc',\n        'self' => $handler->versionedUrl($node->nid),\n      ),\n      array(\n        'id' => $nodes['abc'],\n        'label' => 'abc',\n        'self' => $handler->versionedUrl($nodes['abc']),\n      ),\n      array(\n        'id' => $nodes['efg'],\n        'label' => 'efg',\n        'self' => $handler->versionedUrl($nodes['efg']),\n      ),\n      array(\n        'id' => $nodes['xyz'],\n        'label' => 'xyz',\n        'self' => $handler->versionedUrl($nodes['xyz']),\n      ),\n    );\n    $this->assertEqual($result, $expected_result, 'Default sort by ID and by label.');\n\n    // Test that the default sort can be overridden.\n    $query['sort'] = 'id';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $nodes['abc'],\n        'label' => 'abc',\n        'self' => $handler->versionedUrl($nodes['abc']),\n      ),\n      array(\n        'id' => $nodes['xyz'],\n        'label' => 'xyz',\n        'self' => $handler->versionedUrl($nodes['xyz']),\n      ),\n      array(\n        'id' => $nodes['efg'],\n        'label' => 'efg',\n        'self' => $handler->versionedUrl($nodes['efg']),\n      ),\n      array(\n        'id' => $node->nid,\n        'label' => 'abc',\n        'self' => $handler->versionedUrl($node->nid),\n      ),\n    );\n    $this->assertEqual($result, $expected_result, 'Sort by ID, overriding default sort.');\n\n    // Illegal sort property.\n    $query['sort'] = 'wrong_key';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Illegal sort property used.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Exception thrown on illegal sort property.');\n    }\n\n    // Illegal sort property, descending.\n    $query['sort'] = '-wrong_key';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Illegal sort property, descending, used.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Exception thrown on illegal sort property, descending.');\n    }\n\n    // Test valid sort with sort params disabled.\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['dataProvider']['urlParams'] = array(\n      'filter' => TRUE,\n      'sort' => FALSE,\n      'range' => TRUE,\n    );\n    $handler->setPluginDefinition($plugin_definition);\n    // Re-instantiate the data provider.\n    $handler->setDataProvider(NULL);\n    $query['sort'] = 'label,id';\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Exception not raised for disabled sort parameter.');\n    }\n    catch (UnprocessableEntityException $e) {\n      $this->pass('Exception raised for disabled sort parameter.');\n    }\n\n    // Test the range overrides.\n    unset($query['sort']);\n    $query['range'] = 2;\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(count($result), $query['range'], 'Range parameter overridden correctly');\n\n    // Test the max cap in the the annotation configuration.\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['range'] = 1;\n    $handler->setPluginDefinition($plugin_definition);\n    $query['range'] = 2;\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doGet('', $query), 'json'));\n    $this->assertEqual(count($result['data']), $query['range'], 'Range is limited to the configured maximum.');\n\n    // Test invalid range.\n    $query['range'] = $this->randomName();\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Exception not raised on invalid range parameter.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Exception raised on invalid range parameter.');\n    }\n\n    // Test valid range with range params disabled.\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['dataProvider']['urlParams'] = array(\n      'filter' => TRUE,\n      'sort' => TRUE,\n      'range' => FALSE,\n    );\n    // Unset the previously added range.\n    unset($plugin_definition['range']);\n    $handler->setPluginDefinition($plugin_definition);\n    // Re-instantiate the data provider.\n    $handler->setDataProvider(NULL);\n    $query['range'] = 2;\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Exception not raised for disabled range parameter.');\n    }\n    catch (UnprocessableEntityException $e) {\n      $this->pass('Exception raised for disabled range parameter.');\n    }\n\n    // Sort by an entity metadata wrapper property that is different from the\n    // DB column name.\n    $handler = $resource_manager->getPlugin('articles:1.5');\n    $query = array('sort' => '-user');\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n\n    $this->assertEqual($result[0]['user']['id'], 3, 'List sorted by the \"author\" entity metadata wrapper property, which maps to the \"uid\" DB column name.');\n\n    $query = array('sort' => 'static');\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Exception not thrown for invalid sort.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Exception thrown for invalid sort.');\n    }\n  }\n\n  /**\n   * Test filtering.\n   */\n  public function testFilter() {\n    $resource_manager = restful()->getResourceManager();\n    $user1 = $this->drupalCreateUser();\n    $user2 = $this->drupalCreateUser();\n\n    $this->addIntegerFields();\n    $info = array(\n      array(\n        'title' => 'abc',\n        'integer_single' => 1,\n        'integer_multiple' => array(1, 2, 3),\n        'uid' => $user1->uid,\n      ),\n      array(\n        'title' => 'another abc',\n        'integer_single' => 5,\n        'integer_multiple' => array(3, 4, 5),\n        'uid' => $user1->uid,\n      ),\n      array(\n        'title' => 'last',\n        'integer_single' => NULL,\n        'integer_multiple' => array(),\n        'uid' => $user2->uid,\n      ),\n    );\n\n    $nodes = array();\n\n    foreach ($info as $row) {\n      $title = $row['title'];\n\n      $settings = array(\n        'type' => 'article',\n        'title' => $title,\n      );\n\n      $settings['integer_single'][LANGUAGE_NONE][0]['value'] = $row['integer_single'];\n\n      foreach ($row['integer_multiple'] as $key => $value) {\n        $settings['integer_multiple'][LANGUAGE_NONE][$key]['value'] = $value;\n      }\n\n      $settings['uid'] = $row['uid'];\n\n      $node = $this->drupalCreateNode($settings);\n      $nodes[$title] = $node->nid;\n    }\n\n    $handler = $resource_manager->getPlugin('test_articles:1.2');\n    $fields = array(\n      'id',\n      'label',\n      'integer_single',\n      'intger_multiple',\n    );\n    $query['fields'] = implode(',', $fields);\n\n\n    // Single value property.\n    $query['filter'] = array('label' => 'abc');\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['id'], $nodes['abc'], 'Filter list by single value property.');\n\n    // Assert count is correct.\n    $formatter_handler = restful()\n      ->getFormatterManager()\n      ->getPlugin('hal_json');\n    $instance_configuration = $formatter_handler->getConfiguration();\n    $formatter_handler->setConfiguration(array_merge($instance_configuration ?: array(), array(\n      'resource' => $handler,\n    )));\n    $output = $formatter_handler->prepare($result);\n    $this->assertEqual($output['count'], 1, '\"count\" property is correct.');\n\n    // Single value field.\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    $handler = $resource_manager->getPlugin('test_articles:1.2');\n\n    $query['filter'] = array('integer_single' => '1');\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['id'], $nodes['abc'], 'Filter list by Single value field.');\n\n    // LIKE operator.\n    $input['filter'] = array(\n      'label' => array(\n        'value' => '%nothe%',\n        'operator' => 'LIKE',\n      ),\n    );\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doGet('', $input), 'json'));\n    $result = $result['data'];\n\n    $this->assertEqual($result[0]['id'], $nodes['another abc'], 'Filter list using LIKE operator.');\n\n    // STARTS_WITH operator.\n    $input['filter'] = array(\n      'label' => array(\n        'value' => 'las',\n        'operator' => 'STARTS_WITH',\n      ),\n    );\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doGet('', $input), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['id'], $nodes['last'], 'Filter list using STARTS_WITH operator.');\n\n    // CONTAINS operator.\n    $input['filter'] = array(\n      'label' => array(\n        'value' => 'bc',\n        'operator' => 'CONTAINS',\n      ),\n    );\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doGet('', $input), 'json'));\n    $result = $result['data'];\n\n    // Sort the results before checking it.\n    usort($result, function ($a, $b) {\n      return strcmp($a['label'], $b['label']);\n    });\n    $this->assertEqual($result[0]['id'], $nodes['abc'], 'Filter list using CONTAINS operator.');\n    $this->assertEqual($result[1]['id'], $nodes['another abc'], 'Filter list using CONTAINS operator.');\n\n    // Multiple value field.\n    $query['filter'] = array(\n      'integer_multiple' => array(\n        'value' => array(4, 5),\n        'operator' => 'BETWEEN',\n      ),\n    );\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['id'], $nodes['another abc'], 'Filter list by multiple value field.');\n\n    // Invalid key.\n    $query['filter'] = array('invalid_key' => '3');\n\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('No exception was thrown on invalid key for filter.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Correct exception was thrown on invalid key for filter.');\n    }\n    catch (\\Exception $e) {\n      $this->fail('Incorrect exception was thrown on invalid key for filter.');\n    }\n\n    // Assert filtering doesn't apply for non-list request\n    // (e.g. /api/v1.0/articles/1?filter[label]=foo), as this might be called\n    // from a formatter plugin, after RESTful's error handling has finished.\n    $query_string = array('filter' => array('invalid-key' => 'foo'));\n    $result = $this->httpRequest('api/v1.0/articles/1', RequestInterface::METHOD_GET, $query_string);\n    $this->assertEqual($result['code'], '200', 'Invalid filter key was ignored on non-list query.');\n\n    // Test multiple filters on the same field.\n    $query = array(\n      'filter' => array(\n        'integer_single' => array(\n          'value' => array(1, 4),\n          'operator' => array('>', '<>'),\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($nodes['another abc'], $result[0]['id']);\n\n    $query = array(\n      'filter' => array(\n        'integer_single' => array(\n          'value' => array(1, 5),\n          'operator' => array('>', '<>'),\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result, array());\n\n    $query = array(\n      'filter' => array(\n        'integer_multiple' => array(\n          'value' => array(3, 4),\n        ),\n      ),\n    );\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($nodes['another abc'], $result[0]['id']);\n\n    // Test valid filter with filter params disabled.\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['dataProvider']['urlParams'] = array(\n      'filter' => FALSE,\n      'sort' => TRUE,\n      'range' => TRUE,\n    );\n    $handler->setPluginDefinition($plugin_definition);\n    $handler->setDataProvider(NULL);\n\n    $query['filter'] = array('label' => 'abc');\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Exception not raised for disabled filter parameter.');\n    }\n    catch (UnprocessableEntityException $e) {\n      $this->pass('Exception raised for disabled filter parameter.');\n    }\n\n    // Filter by an entity metadata wrapper property that is different from the\n    // DB column name.\n    $handler = $resource_manager->getPlugin('articles:1.5');\n    $query = array(\n      'filter' => array(\n        'user' => array(\n          'value' => $user1->uid,\n        ),\n      ),\n    );\n\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(count($result), 2, 'List filtered by the \"author\" entity metadata wrapper property, which maps to the \"uid\" DB column name.');\n\n    $query = array(\n      'filter' => array(\n        'static' => array(\n          'value' => 0,\n        ),\n      ),\n    );\n\n    $handler->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Illegal filter property used.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Exception thrown on illegal filter property.');\n    }\n\n  }\n\n  /**\n   * Test pagination.\n   */\n  public function testPagination() {\n    $resource_manager = restful()->getResourceManager();\n    foreach (range(1, 9) as $key) {\n      $settings = array(\n        'type' => 'article',\n        'title' => $key,\n      );\n      $this->drupalCreateNode($settings);\n    }\n\n    $handler = $resource_manager->getPlugin('articles:1.0');\n    $formatter_handler = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter('');\n    $instance_configuration = $formatter_handler->getConfiguration();\n    $formatter_handler->setConfiguration(array_merge($instance_configuration ?: array(), array(\n      'resource' => $handler,\n    )));\n    // Set a smaller range for the pagination.\n    $data_provider = $handler->getDataProvider();\n    $data_provider->setRange(3);\n\n    // Check pagination of first page.\n    $handler->setRequest(Request::create('', array('page' => 1), RequestInterface::METHOD_GET));\n    $handler->setPath('');\n    $result = drupal_json_decode($formatter_handler->format($handler->process()));\n    $this->assertEqual(count($result['data']), 3);\n    $this->assertTrue($result['next'], '\"Next\" link exists on the first page.');\n    $this->assertTrue(empty($result['previous']), '\"Previous\" link does not exist on the first page.');\n\n    // Check pagination of middle pages.\n    $handler->setRequest(Request::create('', array('page' => 2), RequestInterface::METHOD_GET));\n    $result = drupal_json_decode($formatter_handler->format($handler->process()));\n    $this->assertTrue($result['next'], '\"Next\" link exists on the middle page.');\n    $this->assertEqual($result['next']['href'], $handler->versionedUrl('', array(\n      'query' => array('page' => array('number' => 3)),\n    )));\n    $this->assertTrue($result['previous'], '\"Previous\" link exists on the middle page.');\n    $this->assertEqual($result['previous']['href'], $handler->versionedUrl('', array(\n      'query' => array('page' => array('number' => 1)),\n    )));\n\n    // Check pagination of last page.\n    $handler->setRequest(Request::create('', array('page' => 3), RequestInterface::METHOD_GET));\n    $result = drupal_json_decode($formatter_handler->format($handler->process()));\n    $this->assertTrue(empty($result['next']), '\"Next\" link does not exist on the last page.');\n    $this->assertTrue($result['previous'], '\"Previous\" link exists on the last page.');\n\n    // Check other query strings are retained in the _links.\n    $handler->setRequest(Request::create('', array(\n      'page' => 3,\n      'sort' => '-id',\n    ), RequestInterface::METHOD_GET));\n    $result = drupal_json_decode($formatter_handler->format($handler->process()));\n    $this->assertTrue(strpos($result['previous']['href'], 'sort=-id'), 'Query strings are retained in the _links.');\n\n    // Check pagination with non-numeric value.\n    $handler->setRequest(Request::create('', array('page' => 'string'), RequestInterface::METHOD_GET));\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('No exception thrown for pagination with non-numeric value.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Correct exception thrown for pagination with non-numeric value.');\n    }\n    catch (\\Exception $e) {\n      $this->fail('Incorrect exception thrown for pagination with non-numeric value.');\n    }\n\n\n    // Check pagination with 0 value.\n    $handler->setRequest(Request::create('', array('page' => 0), RequestInterface::METHOD_GET));\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('No exception thrown for pagination with 0 value.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Correct exception thrown for pagination with 0 value.');\n    }\n    catch (\\Exception $e) {\n      $this->fail('Incorrect exception thrown for pagination with 0 value.');\n    }\n\n    // Check pagination with high number, where there are not items, yielded no\n    // results, but is a valid call.\n    $handler->setRequest(Request::create('', array('page' => 100), RequestInterface::METHOD_GET));\n    $result = drupal_json_decode($formatter_handler->format($handler->process()));\n    $this->assertEqual($result['data'], array(), 'pagination with high number, where there are not items yielded no results.');\n\n    // Check total number of results.\n    $handler->setRequest(Request::create('', array('page' => 3), RequestInterface::METHOD_GET));\n    $result = drupal_json_decode($formatter_handler->format($handler->process()));\n    $this->assertEqual($result['count'], 9, 'Total count exists and is correct.');\n  }\n\n  /**\n   * Helper function; Add single and multiple integer fields.\n   */\n  private function addIntegerFields() {\n    // Integer - single.\n    $field = array(\n      'field_name' => 'integer_single',\n      'type' => 'number_integer',\n      'entity_types' => array('node'),\n      'cardinality' => 1,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'field_name' => 'integer_single',\n      'bundle' => 'article',\n      'entity_type' => 'node',\n      'label' => t('Integer single'),\n    );\n    field_create_instance($instance);\n\n    // Integer - multiple.\n    $field = array(\n      'field_name' => 'integer_multiple',\n      'type' => 'number_integer',\n      'entity_types' => array('node'),\n      'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'field_name' => 'integer_multiple',\n      'bundle' => 'article',\n      'entity_type' => 'node',\n      'label' => t('Integer multiple'),\n    );\n    field_create_instance($instance);\n  }\n\n  /**\n   * Test error handling when no access is granted to an entity in a list.\n   */\n  public function testAccessHandling() {\n    $resource_manager = restful()->getResourceManager();\n    $settings = array(\n      'type' => 'article',\n    );\n\n    $node1 = $this->drupalCreateNode($settings);\n    $node2 = $this->drupalCreateNode($settings);\n    $node3 = $this->drupalCreateNode($settings);\n\n    $user1 = $this->drupalCreateUser();\n\n    // Deny access via hook_node_access() to a specific node.\n    restful_test_deny_access_node($node2->nid);\n\n    variable_set('restful_show_access_denied', TRUE);\n    $handler = $resource_manager->getPlugin('articles:1.0');\n    $handler->setAccount($user1);\n\n    $handler->setRequest(Request::create('api/articles/v1.0'));\n    $handler->setPath('');\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n\n    $this->assertEqual(count($result['data']), 2, 'List returned and ignored un-accessible entity.');\n    $this->assertEqual(count($result['denied']), 1, 'A denied entity was detected.');\n\n    // Get a list with specific IDs.\n    $ids = array(\n      $node1->nid,\n      $node2->nid,\n      $node3->nid,\n    );\n    $handler->setRequest(Request::create('api/articles/v1.0' . implode(',', $ids)));\n    $handler->setPath(implode(',', $ids));\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $this->assertEqual(count($result['data']), 2, 'List of specific items returned and ignored un-accessible entity.');\n    $this->assertEqual(count($result['denied']), 1, 'A denied entity was detected.');\n  }\n\n  /**\n   * Test node count and pager when there are unpublished nodes.\n   */\n  public function testCountWithUnpublished() {\n    foreach (range(1, 9) as $key) {\n      $settings = array(\n        'type' => 'article',\n        'title' => $key,\n        'status' => NODE_PUBLISHED,\n      );\n      $this->drupalCreateNode($settings);\n    }\n    foreach (range(1, 3) as $key) {\n      $settings = array(\n        'type' => 'article',\n        'title' => $key,\n        'status' => NODE_NOT_PUBLISHED,\n      );\n      $this->drupalCreateNode($settings);\n    }\n\n    $handler = restful()->getResourceManager()->getPlugin('articles:1.0');\n    $formatter = restful()->getFormatterManager()->getPlugin('json');\n    $formatter->setResource($handler);\n    // Set a range for pagination to check only .\n    $handler->getDataProvider()->setRange(9);\n\n    // Check pagination of first page.\n    $result = $handler->doGet('', array('page' => 1));\n    $output = drupal_json_decode($formatter->format($result));\n    $this->assertEqual(count($result), 9, 'Number of results displayed');\n    $this->assertEqual(count($result), $handler->getDataProvider()\n      ->count(), 'Count of results takes into account unpublished nodes');\n    $this->assertTrue(empty($output['next']), '\"Next\" link does not exist on the first page.');\n    $this->assertTrue(empty($output['previous']), '\"Previous\" link does not exist on the first page.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulPassThroughTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulPassThroughTestCase\n */\n\nclass RestfulPassThroughTestCase extends RestfulCurlBaseTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Pass through',\n      'description' => 'Test the pass-through configuration.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * The name of the test table.\n   *\n   * @var string\n   */\n  protected $tableName = 'restful_test_db_query';\n\n  function setUp() {\n    parent::setUp('restful_test', 'restful_example');\n  }\n\n  /**\n   * Test the pass-through property for an entity.\n   */\n  public function testEntity() {\n    $handler = restful_get_restful_handler('articles', 1, 1);\n    $base_request = array('label' => $this->randomName());\n    $this->validatePassThrough($handler, $base_request, TRUE);\n  }\n\n  /**\n   * Test the pass-through property for an entity.\n   */\n  public function testDbQuery() {\n    $handler = restful_get_restful_handler('db_query_test');\n    $base_request = array(\n      'integer' => 1,\n      'string' => $this->randomName(),\n    );\n    $this->validatePassThrough($handler, $base_request);\n  }\n\n  /**\n   * Validate the pass-through for different handlers.\n   *\n   * @param RestfulInterface $handler\n   *   The handler object.\n   * @param array $base_request\n   *   The base request to create or update.\n   */\n  protected function validatePassThrough(\\RestfulInterface $handler, array $base_request = array()) {\n    $request = $base_request;\n    $public_fields = $handler->getPublicFields();\n    $public_fields['foo'] = array(\n      'create_or_update_passthrough' => TRUE,\n    );\n    $handler->setPublicFields($public_fields);\n\n    $result = $handler->post('', $request);\n    $this->assertTrue($result[0]['id'], 'Object was created without a pass-through public field.');\n\n    $request['foo'] = 'bar';\n    $result = $handler->post('', $request);\n    $this->assertTrue($result[0]['id'], 'Object was created with a pass-through public field.');\n\n    // Assert update.\n    $id = $result[0]['id'];\n    $result = $handler->put($id, $request);\n    $this->assertTrue($result[0]['id'], 'Object was updated with a pass-through public field.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulRateLimitTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulRateLimitTestCase.\n */\n\nuse Drupal\\restful\\Exception\\FloodException;\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulRateLimitTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Rate limits',\n      'description' => 'Test the rate limit feature.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example');\n    $settings = array('type' => 'article');\n\n    $titles = array(\n      'abc',\n      'xyz',\n      'efg',\n    );\n    foreach ($titles as $title) {\n      $settings['title'] = $title;\n      $node = $this->drupalCreateNode($settings);\n      $nodes[$title] = $node->nid;\n    }\n  }\n\n  /**\n   * Tests global rate limits.\n   */\n  public function testGlobalLimits() {\n    // Test the global limit.\n    variable_set('restful_global_rate_limit', 1);\n    // P3D for 3 days period. See\n    // http://php.net/manual/en/class.dateinterval.php for more information\n    // about the interval format.\n    variable_set('restful_global_rate_period', 'P3D');\n\n    $account = $this->drupalCreateUser();\n    $this->roleExecute($account, 1, array('articles', 1, 0));\n  }\n\n  /**\n   * Tests the rate limits and its expiration feature.\n   */\n  public function testLimits() {\n    variable_del('restful_global_rate_limit');\n    variable_del('restful_global_rate_period');\n    // This handler has a limit of 2 requests for the anonymous user.\n    $account = drupal_anonymous_user();\n    $this->roleExecute($account, 2, array('articles', 1, 4));\n\n    // This handler has a limit of 3 requests for the authenticated user.\n    $account = $this->drupalCreateUser();\n    $this->roleExecute($account, 3, array('articles', 1, 4));\n\n    // Now that the limit has been reached for $account. Fake expiration and see\n    // that the limit has been renewed.\n    $query = new \\EntityFieldQuery();\n    $results = $query\n      ->entityCondition('entity_type', 'rate_limit')\n      ->entityCondition('bundle', 'request')\n      ->propertyCondition('identifier', 'articles:1.4:request:' . $account->uid)\n      ->execute();\n    $rl = entity_load_single('rate_limit', key($results['rate_limit']));\n    $rl->timestamp = REQUEST_TIME - 2;\n    $rl->expiration = REQUEST_TIME - 1;\n    $rl->save();\n    $this->roleExecute($account, 3, array('articles', 1, 4));\n  }\n\n  /**\n   * Tests the total amount of allowed calls and the following fail.\n   *\n   * @param object $account\n   *   The user account object.\n   * @param int $limit\n   *   The number of calls allowed for a user with the same roles as $account.\n   * @param array $resource_options\n   *   Array of options as received in restful_get_restful_handler.\n   */\n  protected function roleExecute($account, $limit, array $resource_options) {\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPlugin($resource_options[0] . ':' . $resource_options[1] . '.' . $resource_options[2]);\n    $handler->setAccount($account);\n\n    // Test rate limits.\n    $handler->setRequest(Request::create(''));\n    $handler->setPath('');\n    for ($count = 0; $count < $limit; $count++) {\n      try {\n        restful()->getFormatterManager()->format($handler->process(), 'json');\n        $this->pass('The rate limit authorized the request.');\n      }\n      catch (FloodException $e) {\n        $this->fail('The rate limit did not authorize the request.');\n      }\n    }\n\n    try {\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('The rate limit authorized the request.');\n    }\n    catch (FloodException $e) {\n      $this->pass('The rate limit did not authorize the request.');\n      $headers = $e->getHeaders();\n      $this->assertTrue(in_array('Retry-After', array_keys($headers)), 'Retry-After header found after rate limit exception.');\n      $this->assertTrue(new \\DateTime($headers['Retry-After']) > new \\DateTime(), 'Retry-After is set to a time in the future.');\n    }\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulReferenceTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulReferenceTestCase.\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\CacheDecoratedDataProvider;\n\n/**\n * Class RestfulReferenceTestCase.\n */\nclass RestfulReferenceTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Referenced resources',\n      'description' => 'Test defining a public field as a resource for base properties (e.g. the UID on the node entity) and fields.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test property reference.\n   */\n  public function testPropertyReference() {\n    $resource_manager = restful()->getResourceManager();\n    $user1 = $this->drupalCreateUser();\n\n    $settings = array(\n      'type' => 'article',\n      'uid' => $user1->uid,\n    );\n    $node1 = $this->drupalCreateNode($settings);\n    $node2 = $this->drupalCreateNode($settings);\n\n    variable_set('restful_test_reference_simple', TRUE);\n    $resource_manager->clearPluginCache('test_articles:1.2');\n    $handler = $resource_manager->getPlugin('test_articles:1.2');\n\n    $handler->setRequest(Request::create('api/test_articles/v1.2/' . $node1->nid));\n    $handler->setPath($node1->nid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['user']['uid'], $user1->uid, 'Property is not defined as resource, thus the referenced entity appears as the entity.');\n\n    variable_set('restful_test_reference_resource', TRUE);\n    $resource_manager->clearPluginCache('test_articles:1.2');\n    $handler = $resource_manager->getPlugin('test_articles:1.2');\n\n    $handler->setRequest(Request::create('api/test_articles/v1.2/' . $node2->nid));\n    $handler->setPath($node2->nid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['user']['id'], $user1->uid, 'Property is defined as resource, thus the referenced entity appears as the rendered resource.');\n  }\n\n  /**\n   * Test field reference.\n   */\n  public function testEntityReference() {\n    $resource_manager = restful()->getResourceManager();\n    restful_test_add_fields();\n\n    foreach (array('entity_reference_single', 'entity_reference_multiple') as $field_name) {\n      $field = field_info_field($field_name);\n      $field['settings']['target_type'] = 'node';\n      field_update_field($field);\n    }\n\n    $resource_manager->clearPluginCache('main:1.6');\n    $resource_manager->clearPluginCache('test_articles:1.1');\n    $handler = $resource_manager->getPlugin('main:1.6');\n    $node_handler = $resource_manager->getPlugin('test_articles:1.1');\n\n    $user1 = $this->drupalCreateUser();\n    $settings = array(\n      'type' => 'article',\n      'uid' => $user1->uid,\n    );\n    $node1 = $this->drupalCreateNode($settings);\n    $node2 = $this->drupalCreateNode($settings);\n\n    $user1 = $this->drupalCreateUser();\n    $entity1 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $entity1->save();\n\n    $wrapper = entity_metadata_wrapper('entity_test', $entity1);\n    $wrapper->entity_reference_single->set($node1);\n    $wrapper->entity_reference_multiple->set(array($node1, $node2));\n    $wrapper->save();\n\n    $handler->setRequest(Request::create('api/v1.6/main/' . $entity1->pid));\n    $handler->setPath($entity1->pid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $node_handler->setRequest(Request::create('api/v1.1/test_articles' . $node1->nid));\n    $node_handler->setPath($node1->nid);\n    $response1 = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($node_handler->process(), 'json'));\n    $response1 = $response1['data'];\n    $node_handler->setRequest(Request::create('api/v1.1/test_articles' . $node2->nid));\n    $node_handler->setPath($node2->nid);\n    $response2 = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($node_handler->process(), 'json'));\n    $response2 = $response2['data'];\n\n    $expected_result = $response1[0];\n    $this->assertEqual($result[0]['entity_reference_single_resource'], $expected_result, 'Single reference with resource of another entity has correct response.');\n\n    $expected_result = array(\n      $response1[0],\n      $response2[0],\n    );\n\n    $this->assertEqual($result[0]['entity_reference_multiple_resource'], $expected_result, 'Multiple reference with resource of another entity has correct response.');\n\n    // Test the \"fullView\" property on a referenced entity.\n    // We change the definition via the handler instead of creating another\n    // plugin.\n    $resource_field = $handler->getFieldDefinitions()\n      ->get('entity_reference_single_resource');\n    $resource_info = $resource_field->getResource();\n    $resource_info['fullView'] = FALSE;\n    $resource_field->setResource($resource_info);\n    $handler->getFieldDefinitions()\n      ->set('entity_reference_single_resource', $resource_field);\n\n    // Clear cache.\n    $handler->setRequest(Request::create('api/v1.6/main/' . $entity1->pid));\n    $handler->setPath($entity1->pid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['entity_reference_single_resource'], $node1->nid, '\"fullView\" disabled is showing only the entity ID.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulRenderCacheTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulRenderCacheTestCase\n */\n\nuse Doctrine\\Common\\Collections\\ArrayCollection;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\RenderCache\\RenderCache;\n\n/**\n * Class RestfulRenderCacheTestCase.\n */\nclass RestfulRenderCacheTestCase extends \\RestfulCurlBaseTestCase {\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Render Cache',\n      'description' => 'Test the render cache capabilities.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n  }\n\n  /**\n   * Test Render Cache.\n   */\n  public function testRenderCache() {\n    $resource_manager = restful()->getResourceManager();\n    $settings = array('type' => 'article');\n    $account = $this->drupalCreateUser();\n\n    $num_articles = 3;\n    for ($index = 0; $index < $num_articles; $index++) {\n      $settings['title'] = 'Node title ' . $index;\n      $node = $this->drupalCreateNode($settings);\n      $nodes[$node->nid] = $node;\n    }\n\n    /* @var \\Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResourceInterface $handler */\n    $handler = $resource_manager->getPlugin('test_articles:1.1');\n    $handler->setAccount($account);\n    $cache = $handler->getCacheController();\n    // Make sure the cache is activated.\n    $data_provider = $handler->getDataProvider();\n    $options = $data_provider->getOptions();\n    $cache_info = $options['renderCache'];\n    $this->assertTrue($cache_info['render'], 'Cache render is activated');\n\n    // Empty the cache.\n    $cache->clear('*', TRUE);\n    $this->assertTrue($cache->isEmpty(), 'Cache render is empty.');\n\n    // Test that cache is being generated correctly.\n    // Get the articles.\n    drupal_static_reset('Drupal\\restful\\Resource\\ResourceManager::getVersionFromRequest');\n    $handler->setRequest(Request::create(''));\n    $handler->setPath('');\n    $formatter = restful()\n      ->getFormatterManager()\n      ->negotiateFormatter(NULL, 'json');\n    $formatter->setResource($handler);\n    $pre_cache_results = drupal_json_decode($formatter->format($handler->process()));\n    $pre_cache_results = $pre_cache_results['data'];\n    // Make sure some cache entries are generated.\n    $this->assertFalse($cache->isEmpty(), 'Cache render is being populated.');\n    // Get the cached results.\n    $handler->setRequest(Request::create(''));\n    $handler->setPath('');\n    $formatter->setResource($handler);\n    $post_cache_results = drupal_json_decode($formatter->format($handler->process()));\n    $post_cache_results = $post_cache_results['data'];\n    // Make sure the cached results are the same as the non-cached results.\n    $this->assertEqual($pre_cache_results[0], $post_cache_results[0], 'Cached data is consistent.');\n    // Get a cached result directly from the cache backend.\n    $node = reset($nodes);\n    $fragments = new ArrayCollection(array(\n      'resource' => $handler->getResourceName() . '#' . $node->nid,\n      'entity' => 'node#' . $node->nid,\n      'user_id' => (int) $account->uid,\n      'formatter' => 'json',\n    ));\n    $cache_object = RenderCache::create($fragments, $handler->getCacheController());\n    $record = $cache_object->get();\n    $this->assertEqual($pre_cache_results[0], $record->data, 'Data in cache bins is correct.');\n\n    // Test that invalidation is clearing cache records.\n    // 1. Update node and watch cache vanish.\n    // Make sure the cache is activated.\n    $input = array('fields' => 'id,label');\n    $handler->setRequest(Request::create('', $input));\n    $handler->setPath('');\n    restful()->getFormatterManager()->format($handler->process(), 'json');\n    $this->assertTrue($cache_info['simpleInvalidate'], 'Cache render simple invalidation is activated');\n    $node->title .= ' updated';\n    node_save($node);\n    $this->assertFalse($cache_object->get(), 'Cache record cleared correctly.');\n    $this->assertFalse($cache->isEmpty(), 'Remaining cache items are intact after updating entity.');\n    // Regenerate cache for $node.\n    $handler->setRequest(Request::create($node->nid));\n    $handler->setPath($node->nid);\n    restful()->getFormatterManager()->format($handler->process(), 'json');\n    $handler->setRequest(Request::create('', $input));\n    $handler->setPath($node->nid);\n    restful()->getFormatterManager()->format($handler->process(), 'json');\n    $this->assertNotNull($cache_object->get(), 'Cache is being generated for non-list requests.');\n    // 2. Update the user account. All cache records should be invalidated.\n    $account->name .= ' updated';\n    user_save($account);\n    $this->assertFalse($cache_object->get(), 'Cache object has been cleared after updating a user.');\n    // The cache fragment garbage collection happens on shutdown. For testing\n    // purposes we'll call the function directly here.\n    restful_entity_clear_render_cache();\n    // Make sure that the cache fragment entities have been deleted.\n    $query = new \\EntityFieldQuery();\n    /* @var \\Drupal\\restful\\RenderCache\\Entity\\CacheFragmentController $controller */\n    $controller = entity_get_controller('cache_fragment');\n    $results = $query\n      ->entityCondition('entity_type', 'cache_fragment')\n      ->propertyCondition('hash', $controller->generateCacheHash($fragments))\n      ->count()\n      ->execute();\n    $this->assertEqual($results, 0, 'The cache fragment entities were deleted correctly.');\n\n    // Test cache with request params.\n    // Rebuild caches.\n    $cache->clear('*', TRUE);\n\n    $handler->setRequest(Request::create('', $input));\n    $handler->setPath('');\n    $formatter->setResource($handler);\n    $results_w_request = drupal_json_decode($formatter->format($handler->process()));\n    $results_w_request = $results_w_request['data'];\n    $cached_w_request = $cache_object->get()->data;\n    // Check that the results with sparse fieldsets only contain the selected\n    // fields, but the cache contains all fields.\n    $this->assertEqual(array_keys($results_w_request[0]), array(\n      'id',\n      'label',\n    ), 'Response contains only the selected fields.');\n    $this->assertEqual(array_keys($cached_w_request), array(\n      'id',\n      'label',\n      'self',\n    ), 'Cached object contains all the selected fields.');\n\n    // Test helper functions.\n    foreach ($nodes as $nid => $entity) {\n      // Populate the cache.\n      $handler->setRequest(Request::create($nid));\n      $handler->setPath($nid);\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $handler->setRequest(Request::create($nid, $input));\n      $handler->setPath($nid);\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n    }\n\n    // Test PER_ROLE granularity.\n    $cache->clear('*', TRUE);\n\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    // Re-instantiate the data provider.\n    $handler->setDataProvider(NULL);\n    $cache_info['granularity'] = DRUPAL_CACHE_PER_ROLE;\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['renderCache'] = $cache_info;\n    $handler->setPluginDefinition($plugin_definition);\n\n    $handler->setRequest(Request::create(''));\n    $handler->setPath('');\n    restful()->getFormatterManager()->format($handler->process(), 'json');\n    $role_fragments = new ArrayCollection(array(\n      'resource' => $handler->getResourceName() . '#' . $node->nid,\n      'entity' => 'node#' . $node->nid,\n      'user_role' => 'anonymous user,authenticated user',\n      'formatter' => 'json',\n    ));\n    $this->assertTrue($cache->get($controller->generateCacheHash($role_fragments)), 'Cache key contains role information.');\n  }\n\n  /**\n   * Tests for SA 154563.\n   */\n  public function testPageCache() {\n    // Enable page cache.\n    variable_set('cache', TRUE);\n    variable_set('restful_page_cache', TRUE);\n\n    // Make anonymous users not to be able to access content.\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(\n      'access content' => FALSE,\n    ));\n\n    // Create a new article.\n    $settings = array('type' => 'article');\n    $settings['title'] = 'Node title';\n    $node = $this->drupalCreateNode($settings);\n    $path = 'api/v1.0/test_articles/' . $node->nid;\n    $url = url($path, array('absolute' => TRUE));\n    $cache = _cache_get_object('cache_page');\n\n    // Create a user that can access content.\n    $account = $this->drupalCreateUser(array('access content'));\n\n    // 1. Test the cookie authentication.\n    // Log in the user (creating the cookie).\n    $this->drupalLogin($account);\n    // Access the created article creating a page cache entry.\n    $response = $this->httpRequest($path);\n    $this->assertEqual($response['code'], 200, 'Access granted for logged in user.');\n    if (!drupal_is_cli()) {\n      // Make sure that there is not a page cache entry.\n      $this->assertFalse($cache->get($url), 'A page cache entry was not created for a authenticated user.');\n    }\n    // Log out the user.\n    $this->drupalLogout();\n    // Try to access the cached resource.\n    $response = $this->httpRequest($path);\n    // The user should get a 401.\n    $this->assertEqual($response['code'], 401, 'Access denied for anonymous user.');\n    // Clear the cache, since anonymous requests get cached. Requests with basic\n    // authentication will pick that cached version. This is a know issue and we\n    // accept it as a lesser evil.\n    $cache->clear($url);\n\n    // 2. Test the basic authentication.\n    $response = $this->httpRequest($path, RequestInterface::METHOD_GET, NULL, array(\n      'Authorization' => 'Basic ' . drupal_base64_encode($account->name . ':' . $account->pass_raw),\n    ));\n    $this->assertEqual($response['code'], 200, 'Access granted for logged in user.');\n    if (!drupal_is_cli()) {\n      // Make sure that there is a page cache entry.\n      $this->assertFalse($cache->get($url), 'A page cache entry was not created with basic auth.');\n    }\n\n    // Try to access the cached resource.\n    $response = $this->httpRequest($path);\n    // The user should get a 401.\n    $this->assertEqual($response['code'], 401, 'Access denied for anonymous user.');\n    if (!drupal_is_cli()) {\n      // Make sure that there is not a page cache entry.\n      $this->assertFalse($cache->get($url), 'A page cache entry was created for an anonymous user.');\n    }\n    // Remove the cache entry.\n    $cache->clear($url);\n\n    // 3. Test that when restful_page_cache is off there is no page cache.\n    variable_set('restful_page_cache', FALSE);\n    // Try to access the cached resource as anonymous users.\n    $this->httpRequest($path);\n    if (!drupal_is_cli()) {\n      $this->assertFalse($cache->get($url), 'A page cache entry was not created for an anonymous users when restful_page_cache is off.');\n    }\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulSimpleJsonTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulSimpleJsonTestCase\n */\n\nuse Drupal\\restful\\Formatter\\FormatterManager;\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulSimpleJsonTestCase extends RestfulCurlBaseTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'View Simple JSON',\n      'description' => 'Test the viewing of an entity in HAL+JSON format.',\n      'group' => 'RESTful',\n    );\n  }\n\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_test', 'entityreference');\n\n    restful_test_add_fields();\n  }\n\n  /**\n   * Test the Simple JSON formatter.\n   */\n  public function testSimpleJson() {\n    $resource_manager = restful()->getResourceManager();\n    $node = restful_test_create_node_with_tags();\n    $handler = $resource_manager->getPlugin('articles:1.5');\n    $resource_manager->clearPluginCache($handler->getPluginId());\n    // Use the simple JSON formatter.\n    $plugin_definition = $handler->getPluginDefinition();\n    $plugin_definition['formatter'] = 'json';\n    $handler->setPluginDefinition($plugin_definition);\n\n    $handler->setRequest(Request::create('/api/v1.5/articles/' . $node->nid));\n    $handler->setPath($node->nid);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $formatter_manager = new FormatterManager($handler);\n    $accept = empty($GLOBALS['_SERVER']['HTTP_ACCEPT']) ? NULL : $GLOBALS['_SERVER']['HTTP_ACCEPT'];\n    $formatter = $formatter_manager->negotiateFormatter($accept, 'json');\n\n    $result = $formatter->format($response);\n    if ($decoded_json = drupal_json_decode($result)) {\n      $this->pass('Valid JSON output generated.');\n    }\n    else {\n      $this->fail('Invalid JSON output generated.');\n    }\n\n    $this->assertNotNull($decoded_json['data'], 'The \"data\" wrapper was created successfully.');\n\n    // Assert the embedded tags.\n    foreach ($decoded_json['data'][0]['tags'] as $index => $tag_info) {\n      $this->assertNotNull($tag_info['self'], 'The \"self\" property was populated for the tags.');\n      $this->assertNotNull($tag_info['id'], 'The \"id\" property was populated.');\n      $this->assertEqual($tag_info['label'], $response[0]['tags'][$index]['label'], 'The \"label\" property was populated correctly.');\n    }\n\n    // Assert the HATEOAS.\n    // Create another node for pagination.\n    restful_test_create_node_with_tags();\n    // Change the max range.\n    $handler->getDataProvider()->setRange(1);\n    $handler->setRequest(Request::create(''));\n    $handler->setPath('');\n    $results = $handler->process();\n    $formatter = restful()->getFormatterManager()->getPlugin('json');\n    $formatter->setResource($handler);\n    $data = $formatter->prepare($results);\n\n    $this->assertNotNull($data['self'], '\"Self\" property added.');\n    $this->assertEqual($data['count'], 2, 'Count was populated correctly.');\n    $this->assertEqual(count($data['data']), 1, 'The correct number of items was listed.');\n    $this->assertNotNull($data['next'], '\"Next\" property added.');\n\n    // Test the pagination links for bigger ranges.\n    // Create an extra node for more pagination options.\n    restful_test_create_node_with_tags();\n    $handler->getDataProvider()->setRange(50);\n    $handler->setRequest(Request::create('', array(\n      'range' => 1,\n      'page' => 2,\n    )));\n    $handler->setPath('');\n    $results = $handler->process();\n    $formatter = restful()->getFormatterManager()->getPlugin('json');\n    $formatter->setResource($handler);\n    $data = $formatter->prepare($results);\n\n    $this->assertEqual($data['count'], 3, 'Count was populated correctly.');\n    $this->assertEqual(count($data['data']), 1, 'The correct number of items was listed.');\n    $this->assertNotNull($data['next'], '\"Next\" property added.');\n    $this->assertNotNull($data['previous'], '\"Previous\" property added.');\n\n    // Test the max cap for the range.\n    $handler->getDataProvider()->setRange(1);\n    $handler->setRequest(Request::create('/api/v1.5/articles', array(\n      'page' => array(\n        'size' => 1000,\n        'number' => 2,\n      ),\n    )));\n    $handler->setPath('');\n    $results = $handler->process();\n    $formatter = restful()->getFormatterManager()->getPlugin('json');\n    $formatter->setResource($handler);\n    $data = $formatter->prepare($results);\n\n    $this->assertNotNull($data['next'], '\"Next\" property added.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulSubResourcesCreateEntityTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulSubResourcesCreateEntityTestCase.\n */\n\nuse Drupal\\restful\\Exception\\BadRequestException;\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulSubResourcesCreateEntityTestCase extends DrupalWebTestCase {\n\n  /**\n   * Hold the RESTful handler.\n   *\n   * @var \\Drupal\\restful\\Plugin\\resource\\ResourceInterface\n   */\n  protected $handler = NULL;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Sub requests',\n      'description' => 'Test the creation of sub-resources (referenced entities) via sub requests.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test', 'entity_validator_example');\n\n    // Entity reference - single.\n    $field = array(\n      'entity_types' => array('node'),\n      'settings' => array(\n        'handler' => 'base',\n        'target_type' => 'node',\n        'handler_settings' => array(),\n      ),\n      'field_name' => 'entity_reference_single',\n      'type' => 'entityreference',\n      'cardinality' => 1,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'entity_type' => 'node',\n      'field_name' => 'entity_reference_single',\n      'bundle' => 'article',\n      'label' => t('Entity reference single'),\n    );\n\n    field_create_instance($instance);\n\n    // Entity reference - multiple.\n    $field = array(\n      'entity_types' => array('node'),\n      'settings' => array(\n        'handler' => 'base',\n        'target_type' => 'node',\n        'handler_settings' => array(),\n      ),\n      'field_name' => 'entity_reference_multiple',\n      'type' => 'entityreference',\n      'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'entity_type' => 'node',\n      'field_name' => 'entity_reference_multiple',\n      'bundle' => 'article',\n      'label' => t('Entity reference multiple'),\n    );\n\n    field_create_instance($instance);\n\n    $resource_manager = restful()->getResourceManager();\n    $resource_manager->clearPluginCache('test_articles:1.2');\n    $this->handler = $resource_manager->getPlugin('test_articles:1.2');\n    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(\n      'create article content' => TRUE,\n    ));\n  }\n\n  /**\n   * Test creating and updating an entity with sub-resources.\n   */\n  public function testCreateAndUpdateEntity() {\n    $base_request = $request = array(\n      'label' => 'parent',\n      'body' => 'Drupal',\n      'entity_reference_single' => array(\n        'body' => array(\n          'label' => 'child1',\n          'body' => 'Drupal1',\n        ),\n        'request' => array(\n          'method' => 'POST',\n        ),\n      ),\n      'entity_reference_multiple' => array(\n        array(\n          'body' => array(\n            'label' => 'child2',\n            'body' => 'Drupal2',\n          ),\n          'request' => array(\n            'method' => 'POST',\n          ),\n        ),\n        array(\n          'body' => array(\n            'label' => 'child3',\n            'body' => 'Drupal3',\n          ),\n          'request' => array(\n            'method' => 'POST',\n          ),\n        ),\n      ),\n    );\n\n    // POST parent.\n    $this->processRequests('post', '', $request);\n\n    // PUT/ PATCH parent.\n    $settings = array(\n      'type' => 'article',\n      'title' => 'title1',\n    );\n    $node1 = $this->drupalCreateNode($settings);\n    $request = $base_request;\n\n    foreach (array('put', 'patch') as $method) {\n      $this->processRequests($method, $node1->nid, $request);\n    }\n\n    // POST parent, reference existing on single reference, multiple reference\n    // empty.\n\n    $node2 = $this->drupalCreateNode($settings);\n    $node3 = $this->drupalCreateNode($settings);\n    $node4 = $this->drupalCreateNode($settings);\n    $node5 = $this->drupalCreateNode($settings);\n\n    $request = $base_request;\n    $request['entity_reference_single'] = $node1->nid;\n    $request['entity_reference_multiple'] = array(\n      $node2->nid,\n      $node3->nid,\n    );\n    $this->processRequests('post', '', $request);\n\n    // POST parent, reference existing on multiple reference, POST a new one,\n    // PATCH existing one, and PUT existing one.\n    $request = $base_request;\n    $request['entity_reference_single'] = $node2->nid;\n    $request['entity_reference_multiple']['request'] = array(\n      'method' => RequestInterface::METHOD_PATCH,\n    );\n    $request['entity_reference_multiple'] = array(\n      array(\n        // Set the $node3.\n        'id' => $node3->nid,\n      ),\n      array(\n        'body' => array(\n          // Create a new node.\n          'label' => 'POST new one',\n          'body' => 'Drupal',\n        ),\n        'request' => array('method' => 'POST'),\n      ),\n      array(\n        // Set $node4 and update some of the fields.\n        'id' => $node4->nid,\n        'body' => array(\n          'label' => 'PATCH existing one',\n          'body' => 'Drupal',\n        ),\n        'request' => array('method' => 'PATCH'),\n      ),\n      array(\n        // Set $node5 and update some of the fields.\n        'id' => $node5->nid,\n        'body' => array(\n          'label' => 'PATCH existing one',\n          'body' => 'Drupal',\n        ),\n        'request' => array('method' => 'POST'),\n      ),\n    );\n\n    $this->processRequests('post', '', $request);\n\n    // Test the version of the sub-resource.\n    $public_fields = $this->handler->getFieldDefinitions();\n    $erm_resource = $public_fields->get('entity_reference_multiple')\n      ->getResource();\n    $this->assertEqual($erm_resource['majorVersion'], 1, 'Sub resource major version is correct.');\n    $this->assertEqual($erm_resource['minorVersion'], 2, 'Sub resource minor version is correct.');\n  }\n\n  /**\n   * Assert valid and invalid requests.\n   *\n   * @param string $method\n   *   The method name.\n   * @param string $path\n   *   The path.\n   * @param array $request\n   *   The request array.\n   */\n  protected function processRequests($method = 'post', $path = '', array $request = array()) {\n    $method = strtoupper($method);\n    $query = $parsed_body = array();\n    if (Request::isWriteMethod($method)) {\n      $parsed_body = $request;\n    }\n    else {\n      $query = $request;\n    }\n    $this->handler->setRequest(Request::create($path, $query, $method, NULL, FALSE, NULL, array(), array(), array(), $parsed_body));\n    $this->handler->setPath($path);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($this->handler->process(), 'json'));\n    $result = $result['data'][0];\n\n    $this->assertTrue($result['id'], 'Parent entity created.');\n    $this->assertTrue($result['entity_reference_single']['id'], 'Single sub-resource created or updated.');\n    $this->assertTrue($result['entity_reference_multiple'][0]['id'] && $result['entity_reference_multiple'][1]['id'], 'Multiple sub-resource created or updated.');\n\n    // Validation fail on the parent.\n    $request['label'] = 'no';\n    $this->assertInvalidRequest($method, $path, $request);\n\n\n    // Validation fail on the single resource.\n    $request['label'] = 'parent';\n\n    if (is_array($request['entity_reference_single'])) {\n      $request['entity_reference_single']['label'] = 'no';\n      $this->assertInvalidRequest($method, $path, $request);\n      $request['entity_reference_single']['label'] = 'child1';\n    }\n\n\n    // Validation fail on the multiple resource.\n    if (\n      !empty($request['entity_reference_multiple'][0]['label']) &&\n      is_array($request['entity_reference_multiple'][0]['label'])\n    ) {\n      $request['entity_reference_multiple'][0]['label'] = 'no';\n      $this->assertInvalidRequest($method, $path, $request);\n    }\n  }\n\n  /**\n   * Assert an invalid request fails.\n   *\n   * @param string $method\n   *   The method name.\n   * @param string $path\n   *   The path.\n   * @param array $request\n   *   The request array.\n   */\n  protected function assertInvalidRequest($method = 'post', $path = '', array $request = array()) {\n    $method = strtoupper($method);\n    $query = $parsed_body = array();\n    if (Request::isWriteMethod($method)) {\n      $query = $request;\n    }\n    else {\n      $parsed_body = $request;\n    }\n    try {\n      $this->handler->setRequest(Request::create($path, $query, $method, NULL, FALSE, NULL, array(), array(), array(), $parsed_body));\n      $this->handler->setPath($path);\n      $this->handler->process();\n      $this->fail('No exception thrown on validation fail on the parent.');\n    }\n    catch (BadRequestException $e) {\n      $this->pass('Correct exception thrown on validation fail on the parent.');\n    }\n    catch (\\Exception $e) {\n      $this->fail('Wrong exception thrown on validation fail on the parent.');\n    }\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulUpdateEntityCurlTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulUpdateEntityCurlTestCase\n */\n\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulUpdateEntityCurlTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * User account.\n   *\n   * @var stdClass\n   */\n  protected $account;\n\n  public static function getInfo() {\n    return array(\n      'name' => 'Update entity with CURL',\n      'description' => 'Test the updating of an entity using PUT and PATCH methods using CURL.',\n      'group' => 'RESTful',\n    );\n  }\n\n  function setUp() {\n    parent::setUp('restful_test');\n\n    $this->account = $this->drupalCreateUser(array(\n      'administer site configuration',\n      'administer nodes',\n      'edit own article content',\n      'edit any article content',\n    ));\n    $this->drupalLogin($this->account);\n\n    $this->httpauth_credentials = $this->account->name . ':' . $this->account->pass_raw;\n  }\n\n  /**\n   * Test update an entity (PUT & PATCH methods).\n   */\n  function testUpdateEntityAsPutPatch() {\n    // Test update an entity (PUT method).\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n\n    $text = $this->randomName();\n\n    $settings = array(\n      'type' => 'article',\n      'title' => $label,\n    );\n    $settings['body'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $node = $this->drupalCreateNode($settings);\n    $id = $node->nid;\n\n    $request = array('label' => $new_label);\n\n    $result = $this->httpRequest('api/v1.2/test_articles/' . $id, RequestInterface::METHOD_PUT, $request, array(\n      'Content-Type' => 'application/x-www-form-urlencoded',\n    ));\n\n    $expected_result = array(\n      'data' => array(array(\n        'id' => '1',\n        'label' => $new_label,\n        'self' => url('api/v1.2/test_articles/' . $id, array('absolute' => TRUE)),\n        'body' => NULL,\n      )),\n      'self' => array(\n        'href' => url('api/v1.2/test_articles/' . $id, array('absolute' => TRUE)),\n        'title' => 'Self',\n      ),\n    );\n\n    $result = drupal_json_decode($result['body']);\n    $this->assertEqual($expected_result, $result);\n\n    // Update an entity with invalid property name.\n    $request['invalid'] = 'wrong';\n    $result = $this->httpRequest('api/v1.2/test_articles/' . $id, RequestInterface::METHOD_PUT, $request);\n    $this->assertEqual($result['code'], 400, 'User cannot update using PUT method an entity with invalid property name.');\n\n    // Test update an entity (PATCH method).\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n\n    $text = $this->randomName();\n\n    $settings = array(\n      'type' => 'article',\n      'title' => $label,\n    );\n    $settings['body'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $node = $this->drupalCreateNode($settings);\n    $id = $node->nid;\n\n    $request = array('label' => $new_label);\n    $result = $this->httpRequest(\"api/v1.2/test_articles/$id\", RequestInterface::METHOD_PATCH, $request, array(\n      'Content-Type' => 'application/x-www-form-urlencoded',\n    ));\n    $expected_result = array(\n      'data' => array(array(\n        'id' => '2',\n        'label' => $new_label,\n        'self' => url('api/v1.2/test_articles/' . $id, array('absolute' => TRUE)),\n        'body' => $text,\n      )),\n      'self' => array(\n        'title' => 'Self',\n        'href' => url('api/v1.2/test_articles/' . $id, array('absolute' => TRUE)),\n      ),\n    );\n\n    $result = drupal_json_decode($result['body']);\n    $result['data'][0]['body'] = trim(strip_tags($result['data'][0]['body']));\n    ksort($result);\n    ksort($expected_result);\n\n    $this->assertEqual($result, $expected_result);\n\n    // Update an entity with invalid property name.\n    $request['invalid'] = 'wrong';\n    $result = $this->httpRequest(\"api/v1.2/test_articles/$id\", RequestInterface::METHOD_PATCH, $request);\n    $this->assertEqual($result['code'], 400, 'User cannot update using PATCH method an entity with invalid property name.');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulUpdateEntityTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulUpdateEntityTestCase\n */\n\nuse Drupal\\restful\\Http\\Request;\nuse Drupal\\restful\\Http\\RequestInterface;\n\nclass RestfulUpdateEntityTestCase extends DrupalWebTestCase {\n\n  /**\n   * Holds the user account that owns the content.\n   *\n   * @var object\n   */\n  protected $account;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Update entity',\n      'description' => 'Test the updating of an entity using PUT and PATCH methods.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful_test');\n    $this->account = $this->drupalCreateUser(array(\n      'create article content',\n      'edit own article content',\n    ));\n  }\n\n  /**\n   * Test update an entity (PUT method).\n   */\n  public function testUpdateEntityAsPut() {\n    $resource_manager = restful()->getResourceManager();\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n\n    $text = $this->randomName();\n\n    $settings = array(\n      'type' => 'article',\n      'title' => $label,\n      'uid' => $this->account->uid,\n    );\n    $settings['body'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $node = $this->drupalCreateNode($settings);\n    $id = $node->nid;\n\n    $handler = $resource_manager->getPlugin('test_articles:1.2');\n    $handler->setAccount($this->account);\n    $request = array('label' => $new_label);\n\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPut($id, $request), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $id,\n        'label' => $new_label,\n        'self' => $handler->versionedUrl($id),\n        'body' => NULL,\n      ),\n    );\n\n    $this->assertEqual($result, $expected_result);\n\n    // Update an entity with invalid property name.\n    $request['invalid'] = 'wrong';\n    try {\n      $handler->setRequest(Request::create('api/test_articles/v1.2/' . $id, array(), RequestInterface::METHOD_PUT, NULL, FALSE, NULL, array(), array(), array(), $request));\n      $handler->setPath($id);\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('User can update using PUT method an entity with invalid property name.');\n    }\n    catch (Exception $e) {\n      $this->pass('User cannot update using PUT method an entity with invalid property name.');\n    }\n\n\n    $new_label = $this->randomName();\n    $new_body = $this->randomName();\n\n    $request = array(\n      'label' => $new_label,\n      'body' => $new_body,\n    );\n    // Setting new value for 'body'.\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPut($id, $request), 'json'));\n    // Making sure the new body has been set.\n    $this->assertEqual(trim(strip_tags($result['data'][0]['body'])), $new_body);\n\n    // Removing the body value.\n    $request = array(\n      'label' => $new_label,\n      'body' => NULL,\n    );\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPut($id, $request), 'json'));\n    $this->assertEqual($result['data'][0]['body'], NULL);\n  }\n\n  /**\n   * Test update an entity (PATCH method).\n   */\n  function testUpdateEntityAsPatch() {\n    $resource_manager = restful()->getResourceManager();\n    $label = $this->randomName();\n    $new_label = $this->randomName();\n\n    $text = $this->randomName();\n\n    $settings = array(\n      'type' => 'article',\n      'title' => $label,\n      'uid' => $this->account->uid,\n    );\n    $settings['body'][LANGUAGE_NONE][0]['value'] = $text;\n\n    $node = $this->drupalCreateNode($settings);\n    $id = $node->nid;\n\n    $handler = $resource_manager->getPlugin('test_articles:1.2');\n    $handler->setAccount($this->account);\n    $request = array('label' => $new_label);\n\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPatch($id, $request), 'json'));\n    $result = $result['data'];\n    $expected_result = array(\n      array(\n        'id' => $id,\n        'label' => $new_label,\n        'self' => $handler->versionedUrl($id),\n        'body' => $text,\n      ),\n    );\n\n    $result[0]['body'] = trim(strip_tags($result[0]['body']));\n    $this->assertEqual($result, $expected_result);\n\n    // Update an entity with invalid property name.\n    $request['invalid'] = 'wrong';\n    try {\n      $handler->setRequest(Request::create('api/test_articles/v1.2/' . $id, array(), RequestInterface::METHOD_PATCH, NULL, FALSE, NULL, array(), array(), array(), $request));\n      $handler->setPath($id);\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('User can update using PATCH method an entity with invalid property name.');\n    }\n    catch (Exception $e) {\n      $this->pass('User cannot update using PATCH method an entity with invalid property name.');\n    }\n\n    $new_body = $this->randomName();\n    $request = array('body' => $new_body);\n    // Setting new value for 'body'.\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPatch($id, $request), 'json'));\n    // Making sure the new body has been set.\n    $this->assertEqual(trim(strip_tags($result['data'][0]['body'])), $new_body);\n\n    // Removing the body value.\n    $request = array('body' => NULL);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doPatch($id, $request), 'json'));\n    $this->assertEqual($result['data'][0]['body'], NULL);\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulUserLoginCookieTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulUserLoginCookieTestCase.\n */\n\nclass RestfulUserLoginCookieTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * Holds the generated account.\n   *\n   * @var stdClass\n   */\n  protected $account;\n\n  /**\n   * Holds the current value of the $_SERVER super global.\n   *\n   * @var array\n   */\n  protected $originalServer;\n\n  /**\n   * {@inheritdoc}\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Login endpoint',\n      'description' => 'Test the \"/api/login \"endpoint.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function setUp() {\n    parent::setUp('restful');\n\n    $this->originalServer = $_SERVER;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  public function tearDown() {\n    global $user;\n    // Put back the user object.\n    $user = $this->originalUser;\n\n    // Put back the $_SERVER array.\n    $_SERVER = $this->originalServer;\n    parent::tearDown();\n  }\n\n  /**\n   * Test login using curl via /api/login.\n   */\n  public function testLogin() {\n    global $user;\n    // We need to hijack the global user object in order to force it to be an\n    // anonymous user.\n    $user = drupal_anonymous_user();\n\n    $user1 = $this->drupalCreateUser();\n    $this->httpauth_credentials = $user1->name . ':' . $user1->pass_raw;\n\n    $result = $this->httpRequest('api/login');\n    $this->assertEqual($result['code'], '200', '200 status code sent for an anonymous user logging in.');\n\n    // Since we are already logged in, we should get a 403.\n    $result = $this->httpRequest('api/login');\n    $this->assertEqual($result['code'], '403', '403 status code sent for an already logged in user.');\n\n  }\n}\n"
  },
  {
    "path": "tests/RestfulVariableTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulVariableTestCase.\n */\n\nuse Drupal\\restful\\RenderCache\\RenderCache;\n\nclass RestfulVariableTestCase extends DrupalWebTestCase {\n\n  /**\n   * Provides information about the test class.\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'Variable',\n      'description' => 'Test the variable data provider.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * Operations before the testing begins.\n   */\n  public function setUp() {\n    parent::setUp('restful_example');\n  }\n\n  /**\n   * Test authenticating a user.\n   */\n  public function testCrudOperations() {\n    // Set up random content and resource handler.\n    $random_string = $this->randomName();\n    $handler = restful()->getResourceManager()->getPlugin('variables:1.0');\n    $formatter = restful()->getFormatterManager()->negotiateFormatter(NULL, 'json');\n    $formatter->setResource($handler);\n\n    // Populate the test environment with variables.\n    $random_numbers = array();\n    for ($i = 0; $i < 6; $i++) {\n      $random_numbers[] = intval(mt_rand(1, 100));\n      variable_set('variable_' . $i, array('test_data' => $random_numbers[$i]));\n    }\n\n    $this->assertTrue(variable_get('variable_5'), 'The variables have been set.');\n\n    // Testing read.\n    $results = $formatter->prepare($handler->doGet('variable_5'));\n\n    $expected = array('test_data' => $random_numbers[5]);\n\n    $this->assertEqual($results['data'][0]['variable_name'], 'variable_5', 'The variable name was successfully retrieved.');\n    $this->assertEqual($results['data'][0]['variable_value'], $expected, 'The variable value was successfully retrieved.');\n\n    // Testing read context listing.\n    $results = $formatter->prepare($handler->doGet());\n    $in_results = FALSE;\n\n    foreach ($results['data'] as $result) {\n      if ($result['variable_name'] == 'variable_5') {\n        $in_results = TRUE;\n      }\n    }\n    $this->assertTrue($in_results, 'All the content listed successfully.');\n\n\n\n    // Testing sort for read context.\n\n    // Set a variable that will probably sort last.\n    variable_set('zzzzz', 'some value');\n\n    // Find the last variable name, which will probably be the one we just set.\n    $query = array(\n      'sort' => '-variable_name',\n    );\n    $results = $formatter->prepare($handler->doGet('', $query));\n    $last_variable_name = $results['data'][0]['variable_name'];\n\n    // Generate a variable name that will always sort last.\n    $new_variable_name = 'zzz';\n    while (strcmp($new_variable_name, $last_variable_name) <= 0) {\n      $new_variable_name .= 'z';\n    }\n\n    variable_set($new_variable_name, array('key' => $random_string));\n\n    $query = array(\n      'sort' => '-variable_name',\n    );\n    $results = $formatter->prepare($handler->doGet('', $query));\n\n    $expected = array(\n      'variable_name' => $new_variable_name,\n      'variable_value' => array('key' => $random_string),\n    );\n\n    $this->assertEqual($results['data'][0], $expected, 'List is sorted correctly.');\n\n    // Testing create.\n    $parsed_body = array(\n      'variable_name' => 'created_variable',\n      'variable_value' => $random_string,\n    );\n    $handler->doPost($parsed_body);\n    $results = $formatter->prepare($handler->doGet('created_variable'));\n\n    $this->assertEqual($results['data'][0]['variable_name'], 'created_variable', 'The variable was created.');\n    $this->assertEqual($results['data'][0]['variable_value'], $random_string, 'The created variable value is present.');\n\n    // Testing update.\n    $parsed_body = array('variable_name' => 'created_variable');\n    $handler->doPatch('created_variable', $parsed_body);\n    $results = $formatter->prepare($handler->doGet('created_variable'));\n\n    // Fields that are not supplied should not be updated.\n    $this->assertEqual($results['data'][0]['variable_value'], $random_string, 'The variable value was not updated.');\n\n    // Testing replace.\n    $handler->doPut('created_variable', $parsed_body);\n    $results = $formatter->prepare($handler->doGet('created_variable'));\n\n    // Fields that are not supplied should be NULL.\n    $this->assertFalse($results['data'][0]['variable_value'], 'The variable value was removed.');\n\n    // Testing delete.\n    $handler->doDelete('created_variable');\n    $deleted = !variable_get('created_variable');\n    $this->assertTrue($deleted);\n  }\n\n  /**\n   * Test the render cache.\n   */\n  public function testRenderCache() {\n    // Create a test variable.\n    /* @var \\Drupal\\restful\\Plugin\\resource\\Decorators\\CacheDecoratedResource $handler */\n    $handler = restful()->getResourceManager()->getPlugin('variables:1.0');\n    $formatter = restful()->getFormatterManager()->negotiateFormatter(NULL, 'json');\n    $formatter->setResource($handler);\n\n    $parsed_body = array(\n      'variable_name' => 'test_variable_cache',\n      'variable_value' => TRUE,\n    );\n    $handler->doPost($parsed_body);\n    $created = variable_get('test_variable_cache');\n    $this->assertNotNull($created, 'The cache variable has been created.');\n\n    // Populate the cache entries.\n    $account = $this->drupalCreateUser();\n    $handler->setAccount($account);\n    $formatter->prepare($handler->doGet('test_variable_cache'));\n\n    // Get the cache value.\n    $cache_fragments = $handler->getDataProvider()->getCacheFragments('test_variable_cache');\n    $cache_fragments->set('formatter', 'json');\n    $render_cache = RenderCache::create($cache_fragments, $handler->getCacheController());\n    $cache_data = $render_cache->get();\n\n    $this->assertNotNull($cache_data->data, 'Cache data is present.');\n    $this->assertEqual($cache_data->data['variable_name'], 'test_variable_cache', 'The variable name was retrieved from the cache.');\n    $this->assertEqual($cache_data->data['variable_value'], TRUE, 'The variable value was retrieved from the cache.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulViewEntityMultiLingualTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulViewEntityMultiLingualTestCase\n */\n\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulViewEntityMultiLingualTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * The user to run the tests as.\n   */\n  protected $testUser;\n\n  public static function getInfo() {\n    return array(\n      'name' => 'View multilingual entity',\n      'description' => 'Test the viewing of a multilingual entity.',\n      'group' => 'RESTful',\n    );\n  }\n\n  function setUp() {\n    parent::setUp(\n      'restful_example',\n      'restful_test',\n      'entityreference',\n      'locale'\n    );\n\n    $this->testUser = $this->drupalCreateUser(\n      array(\n        'administer languages',\n        'access administration pages',\n        'administer site configuration',\n      )\n    );\n    require_once DRUPAL_ROOT . '/includes/locale.inc';\n    $this->drupalLogin($this->testUser);\n    $languages = language_list();\n    if (!isset($languages['en'])) {\n      locale_add_language('en', NULL, NULL, LANGUAGE_LTR, '', 'en');\n    }\n    if (!isset($languages['fr'])) {\n      locale_add_language('fr', NULL, NULL, LANGUAGE_LTR, '', 'fr');\n    }\n    $this->addTestFields();\n  }\n\n  /**\n   * Add test fields.\n   */\n  protected function addTestFields() {\n    // Text - single.\n    $field = array(\n      'field_name' => 'text_single',\n      'type' => 'text_long',\n      'entity_types' => array('restful_test_translatable_entity'),\n      'cardinality' => 1,\n      'translatable' => TRUE,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'field_name' => 'text_single',\n      'bundle' => 'restful_test_translatable_entity',\n      'entity_type' => 'restful_test_translatable_entity',\n      'label' => t('Text single'),\n      'settings' => array(\n        'text_processing' => 0,\n      ),\n    );\n    field_create_instance($instance);\n    // Text - multiple.\n    $field = array(\n      'field_name' => 'text_multiple',\n      'type' => 'text_long',\n      'entity_types' => array('restful_test_translatable_entity'),\n      'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n      'translatable' => TRUE,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'field_name' => 'text_multiple',\n      'bundle' => 'restful_test_translatable_entity',\n      'entity_type' => 'restful_test_translatable_entity',\n      'label' => t('Text multiple'),\n      'settings' => array(\n        'text_processing' => 0,\n      ),\n    );\n    field_create_instance($instance);\n  }\n\n  /**\n   * Test viewing an entity with translatable fields.\n   */\n  function testViewMultiLangualEntity() {\n    $user = $this->drupalCreateUser();\n    $values = array(\n      'name' => 'restful_test_translatable_entity',\n      'uid' => $user->uid,\n      'label' => 'Test translation',\n    );\n    $entity = entity_create('restful_test_translatable_entity', $values);\n    $wrapper = entity_metadata_wrapper('restful_test_translatable_entity', $entity);\n\n    $text1 = array(\n      'en' => $this->randomName(),\n      'fr' => $this->randomName(),\n    );\n    $text2 = array(\n      'en' => $this->randomName(),\n      'fr' => $this->randomName(),\n    );\n\n    foreach (array('en', 'fr') as $langcode) {\n      $wrapper->language($langcode);\n      $wrapper->text_single->set($text1[$langcode]);\n      $wrapper->text_multiple->set(array($text1[$langcode], $text2[$langcode]));\n    }\n    $wrapper->save();\n\n    $id = $entity->pid;\n    foreach (array('en', 'fr') as $langcode) {\n      $this->assertExpectedResult($langcode, $id, $text1[$langcode], $text2[$langcode]);\n    }\n  }\n\n  /**\n   * Helper to test viewing an entity (GET method) in a certain language.\n   *\n   * @param string $langcode\n   *   The language to view the entity in.\n   * @param int $id\n   *   The ID of the entity to test.\n   * @param string $text1\n   *   The first expected string (text_single and text_multiple[0]).\n   * @param string $text2\n   *   The second expected string (text_multiple[2]).\n   */\n  private function assertExpectedResult($langcode, $id, $text1, $text2) {\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPlugin('restful_test_translatable_entity:1.0');\n    // Explicitly set the langcode.\n    $handler->getDataProvider()->setLangCode($langcode);\n    $handler->setRequest(Request::create('api/restful_test_translatable_entity/' . $id));\n    $handler->setPath($id);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n\n    $this->assertEqual(trim(strip_tags($result['text_single'])), $text1, 'Entity view has correct result for \"text_single\" in language \"' . $langcode . '\".');\n    $this->assertEqual(trim(strip_tags($result['text_multiple'][0])), $text1, 'Entity view has correct result for the first value of \"text_multiple\" in language \"' . $langcode . '\".');\n    $this->assertEqual(trim(strip_tags($result['text_multiple'][1])), $text2, 'Entity view has correct result for the second value of \"text_multiple\" in language \"' . $langcode . '\".');\n  }\n}\n"
  },
  {
    "path": "tests/RestfulViewEntityTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains \\RestfulViewEntityTestCase.\n */\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulViewEntityTestCase extends RestfulCurlBaseTestCase {\n\n  /**\n   * Overrides DrupalWebTestCase::getInfo().\n   */\n  public static function getInfo() {\n    return array(\n      'name' => 'View entity',\n      'description' => 'Test the viewing of an entity.',\n      'group' => 'RESTful',\n    );\n  }\n\n  /**\n   * Overrides DrupalWebTestCase::setUp().\n   */\n  public function setUp() {\n    parent::setUp('restful_example', 'restful_test', 'entityreference');\n\n    restful_test_add_fields();\n  }\n\n  /**\n   * Test viewing an entity (GET method).\n   *\n   * v1.0 - Simple entity view (id, label, self).\n   * v1.1 - Text and entity reference fields.\n   * v1.2 - \"callback\" and \"process callback\".\n   * v1.3 - Non-existing \"callback\" property.\n   * v1.4 - Non-existing \"process callback\" property.\n   * v1.6 - XML output format.\n   */\n  public function testViewEntity() {\n    $user1 = $this->drupalCreateUser();\n    $entity1 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $entity1->save();\n\n    $entity2 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $entity2->save();\n\n    $entity3 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $wrapper = entity_metadata_wrapper('entity_test', $entity3);\n\n    $text1 = $this->randomName();\n    $text2 = $this->randomName();\n\n\n    $wrapper->text_single->set($text1);\n    $wrapper->text_multiple->set(array($text1, $text2));\n\n    $wrapper->entity_reference_single->set($entity1);\n    $wrapper->entity_reference_multiple[] = $entity1;\n    $wrapper->entity_reference_multiple[] = $entity2;\n\n    $wrapper->save();\n\n    $id = $entity3->pid;\n\n    $base_expected_result = array(\n      'id' => $id,\n      'label' => 'Main test type',\n    );\n\n    $resource_manager = restful()->getResourceManager();\n\n    // v1.0 - Simple entity view (id, label, self).\n    $handler = $resource_manager->getPlugin('main:1.0');\n    $base_expected_result['self'] = $handler->versionedUrl($id);\n    $expected_result = $base_expected_result;\n\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->doGet($id), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $this->assertEqual($result, $expected_result, 'Entity view has expected result for \"main\" resource v1');\n\n    // v1.1 - Text and entity reference field.\n    $handler = $resource_manager->getPlugin('main:1.1');\n    $request = Request::create('api/main/v1.1/' . $id);\n    $handler->setRequest($request);\n    $base_expected_result['self'] = $handler->versionedUrl($id);\n    $handler->setPath($id);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n\n    $base_expected_result_v1 = $base_expected_result;\n\n    // NULL fields.\n    $base_expected_result_v1 += array(\n      'text_single_processing' => NULL,\n      'text_multiple_processing' => NULL,\n      'term_single' => NULL,\n      'term_multiple' => NULL,\n      'file_single' => NULL,\n      'file_multiple' => NULL,\n      'image_single' => NULL,\n      'image_multiple' => NULL,\n    );\n\n    $expected_result = $base_expected_result_v1;\n    $expected_result['text_single'] = $text1;\n    $expected_result['text_multiple'] = array($text1, $text2);\n    $expected_result['entity_reference_single'] = $entity1->pid;\n    $expected_result['entity_reference_multiple'] = array(\n      $entity1->pid,\n      $entity2->pid,\n    );\n\n    $request = Request::create('api/main/v1.1/' . $entity1->pid);\n    $handler->setRequest($request);\n    $handler->setPath($entity1->pid);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $expected_result['entity_reference_single_resource'] = $response[0];\n    $response1 = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process()));\n    $response1 = $response1['data'];\n\n    $request2 = Request::create('api/main/v1.1/' . $entity2->pid);\n    $handler->setRequest($request2);\n    $response2 = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process()));\n    $response2 = $response2['data'];\n    $expected_result['entity_reference_multiple_resource'] = array(\n      $response1[0],\n      $response2[0],\n    );\n\n    $stripped_result = $result;\n    $stripped_result['text_single'] = trim(strip_tags($result['text_single']));\n    $stripped_result['text_multiple'][0] = trim(strip_tags($result['text_multiple'][0]));\n    $stripped_result['text_multiple'][1] = trim(strip_tags($result['text_multiple'][1]));\n\n    ksort($stripped_result);\n    ksort($expected_result);\n    $this->assertFalse(drupal_array_diff_assoc_recursive($result, $stripped_result), 'Entity view has correct result for \"main\" resource v1.1');\n\n    // Test the \"fullView\" property on a referenced entity.\n    // We change the definition via the handler instead of creating another\n    // plugin.\n    $field_definitions = $handler->getFieldDefinitions();\n    // Single entity reference field with \"resource\".\n    $reference_field = $field_definitions->get('entity_reference_single_resource');\n    $reference_field->setResource(array(\n      'name' => 'main',\n      'fullView' => FALSE,\n    ));\n    $field_definitions->set('entity_reference_single_resource', $reference_field);\n    $handler->setFieldDefinitions($field_definitions);\n\n    $request = Request::create('api/main/v1.1/' . $id);\n    $handler->setRequest($request);\n    $handler->setPath($id);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual($result[0]['entity_reference_single_resource'], $entity1->pid, '\"fullView\" property is working properly.');\n\n    // Empty the text and entity reference fields.\n    $wrapper->text_single->set(NULL);\n    $wrapper->text_multiple->set(NULL);\n    $wrapper->entity_reference_single->set(NULL);\n    $wrapper->entity_reference_multiple->set(NULL);\n    $wrapper->save();\n\n    $handler->setRequest($request);\n    $handler->setPath($id);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $expected_result = $base_expected_result_v1;\n    $expected_result['text_single'] = NULL;\n    $expected_result['text_multiple'] = NULL;\n    $expected_result['text_single'] = NULL;\n    $expected_result['text_multiple'] = NULL;\n    $expected_result['entity_reference_single'] = NULL;\n    $expected_result['entity_reference_multiple'] = NULL;\n    $expected_result['entity_reference_single_resource'] = NULL;\n    $expected_result['entity_reference_multiple_resource'] = NULL;\n\n    ksort($result);\n    ksort($expected_result);\n    $this->assertEqual($result, $expected_result, 'Entity view has correct result for \"main\" resource v1.1 with empty entity reference.');\n\n\n    // Load an entity by an alternate field.\n    $entity4 = entity_create('entity_test', array(\n      'name' => 'main',\n      'uid' => $user1->uid,\n    ));\n    $wrapper = entity_metadata_wrapper('entity_test', $entity4);\n    $text = $this->randomName();\n    $wrapper->text_single->set($text);\n    $wrapper->save();\n\n    $request = Request::create('api/main/v1.1/' . $text, array('loadByFieldName' => 'text_single'));\n    $handler->setRequest($request);\n    $handler->setPath($text);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertNotNull($result[0]);\n\n    // Make sure canonical header is added.\n    $result = $this->httpRequest('api/main/v1.1/' . $text, RequestInterface::METHOD_GET, array('loadByFieldName' => 'text_single'));\n    $canonical_link = $handler->versionedUrl($wrapper->getIdentifier(), array(), FALSE) . '; rel=\"canonical\"';\n    $this->assertTrue(strpos($result['headers'], $canonical_link));\n\n    // v1.2 - \"callback\" and \"process callback\".\n    $handler = $resource_manager->getPlugin('main:1.2');\n    $request = Request::create('api/main/v1.2/' . $id);\n    $handler->setRequest($request);\n    $base_expected_result['self'] = $handler->versionedUrl($id);\n    $handler->setPath($id);\n    $response = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $response = $response['data'];\n    $result = $response[0];\n    $expected_result = $base_expected_result;\n    $expected_result['callback'] = 'callback';\n    $expected_result['process_callback_from_callback'] = 'callback processed from callback';\n    $expected_result['process_callback_from_value'] = $id . ' processed from value';\n    $this->assertEqual($result, $expected_result, 'Entity view has correct result for \"main\" resource v1.2');\n\n    // v1.3 - Non-existing \"callback\" property.\n    $handler = $resource_manager->getPlugin('main:1.3');\n    $request = Request::create('api/main/v1.3/' . $id);\n    $handler->setRequest($request);\n    try {\n      $handler->setPath($id);\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Non-existing \"callback\" property did not trigger an exception.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-existing \"callback\" property triggered an exception.');\n    }\n\n    // v1.4 - Non-existing \"process callback\" property.\n    $handler = $resource_manager->getPlugin('main:1.4');\n    $request = Request::create('api/main/v1.4/' . $id);\n    $handler->setRequest($request);\n    try {\n      $handler->setPath($id);\n      restful()->getFormatterManager()->format($handler->process(), 'json');\n      $this->fail('Non-existing \"process callback\" property did not trigger an exception.');\n    }\n    catch (Exception $e) {\n      $this->pass('Non-existing \"process callback\" property triggered an exception.');\n    }\n\n    // v1.6 - XML output format.\n    $settings = array(\n      'type' => 'article',\n      'uid' => $user1->uid,\n    );\n    $node = $this->drupalCreateNode($settings);\n\n    $response = $this->httpRequest('api/v1.6/articles', RequestInterface::METHOD_GET);\n    // Returns something like:\n    // <api>\n    //   <data>\n    //     <item0>\n    //       <id>1</id>\n    //       <label>Foo</label>\n    //       <self>http://example.com/node/1</self>\n    //       <body>...</body>\n    //     </item0>\n    //   </data>\n    //   <count>50</count>\n    //   <_links>\n    //     <next>https://example.com/api/v1.0/articles</next>\n    //   </_links>\n    // </api>\n\n    $xml = new SimpleXMLElement($response['body']);\n    $results = $xml->xpath('/api/_embedded/articles/item0/label');\n    $result = reset($results);\n\n    $this->assertEqual($node->title, $result->__toString(), 'XML parsed correctly.');\n\n    // Test Image variations based on image styles.\n    // Add the multiple images field to the article bundle.\n    $field = array(\n      'field_name' => 'field_images',\n      'type' => 'image',\n      'settings' => array(),\n      'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n    );\n    field_create_field($field);\n\n    $instance = array(\n      'field_name' => 'field_images',\n      'entity_type' => 'node',\n      'label' => 'Image multiple',\n      'bundle' => 'article',\n    );\n    field_create_instance($instance);\n\n    $images = $this->drupalGetTestFiles('image');\n    $image = array_shift($images);\n    $image = file_save((object) $image);\n    // Test multiple Image variations based on image styles.\n    $article = array(\n      'type' => 'article',\n      'field_images' => array(LANGUAGE_NONE => array()),\n      'field_image' => array(LANGUAGE_NONE => array(array('fid' => $image->fid))),\n    );\n    foreach ($images as $image) {\n      $image = file_save((object) $image);\n      $article['field_images'][LANGUAGE_NONE][] = array('fid' => $image->fid);\n    }\n    $article = $this->drupalCreateNode($article);\n    $resource_manager->clearPluginCache('articles:1.5');\n    $handler = $resource_manager->getPlugin('articles:1.5');\n    $request = Request::create('api/v1.5/articles/' . $article->nid);\n    $handler->setRequest($request);\n    $handler->setPath($article->nid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(array_keys($result[0]['image']['styles']) == array(\n        'thumbnail',\n        'medium',\n        'large',\n      ), 'The selected image styles are present.');\n    $this->assertEqual(count(array_filter(array_values($result[0]['image']['styles']))) == 3, 'The image styles are populated.');\n\n    $this->assertEqual(count($result[0]['images']), count($images), 'The number of images is correct.');\n    $this->assertEqual(array_keys($result[0]['images'][0]['styles']) == array(\n        'thumbnail',\n        'medium',\n        'large',\n      ), 'The selected image styles are present.');\n    $this->assertEqual(count(array_filter(array_values($result[0]['images'][0]['styles']))) == 3, 'The image styles are populated.');\n  }\n\n  /**\n   * Test the generation of the Vary headers.\n   */\n  public function testHeaders() {\n    $node = $this->drupalCreateNode(array('type' => 'article'));\n\n    // When there is no header version passed in there is no need of Vary.\n    $response = $this->httpRequest('api/v1.1/articles');\n    $this->assertFalse(preg_match('/X-API-Version/', $response['headers']), 'The Vary header was not added.');\n\n    // Make sure that the version header is present in the response.\n    $this->assertTrue(preg_match('/v1\\.1/', $response['headers']), 'The Vary header was added.');\n\n    $response = $this->httpRequest('api/articles', RequestInterface::METHOD_GET, NULL, array('X-API-Version' => 'v1.1'));\n    $this->assertTrue(preg_match('/X-API-Version/', $response['headers']), 'The Vary header was added.');\n\n    // Make sure that the version header is present in the response.\n    $this->assertTrue(preg_match('/v1\\.1/', $response['headers']), 'The Vary header was added.');\n\n    // Test that if there is no explicit formatter in the plugin definition then\n    // it is selected based on the Accept header.\n    variable_set('restful_default_output_formatter', 'invalid');\n\n    $response = $this->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(\n      'Accept' => 'application/hal+json',\n    ));\n    $this->assertNotNull(drupal_json_decode($response['body']), 'JSON output detected.');\n\n    // Test XML selection.\n    $response = $this->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(\n      'Accept' => 'application/xml',\n    ));\n    $this->assertNotNull(new SimpleXMLElement($response['body']), 'XML output detected.');\n\n    // Test wildcard selection.\n    $response = $this->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(\n      'Accept' => 'application/*',\n    ));\n    $this->assertEqual($response['code'], 200, 'Some output format detected for wildcard Accept.');\n\n    // Test that plugin definition takes precedence.\n    $response = $this->httpRequest('api/v1.6/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(\n      'Accept' => 'application/hal+json',\n    ));\n    $this->assertNotNull(new SimpleXMLElement($response['body']), 'Plugin definition takes precedence.');\n\n    // The following should resolve to the 'invalid' formatter. It should raise\n    // an exception.\n    $response = $this->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(\n      'Accept' => 'non-existing',\n    ));\n    $this->assertEqual($response['code'], 503, 'Error shown for invalid formatter.');\n  }\n\n}\n"
  },
  {
    "path": "tests/RestfulViewModeAndFormatterTestCase.test",
    "content": "<?php\n\n/**\n * @file\n * Contains RestfulViewModeFormatterTestCase\n */\n\nuse Drupal\\restful\\Http\\Request;\n\nclass RestfulViewModeAndFormatterTestCase extends DrupalWebTestCase {\n\n  public static function getInfo() {\n    return array(\n      'name' => 'View mode and formatter',\n      'description' => 'Test the integration with entity view mode and field API formatters.',\n      'group' => 'RESTful',\n    );\n  }\n\n  function setUp() {\n    parent::setUp('restful_example', 'restful_test');\n  }\n\n  /**\n   * Test the view mode integration.\n   */\n  public function testViewModeIntegration() {\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPlugin('articles:1.7');\n    $nodes[] = restful_test_create_node_with_tags();\n    $nodes[] = restful_test_create_node_with_tags();\n    // Make sure to get more than one node.\n    $handler->setRequest(Request::create('api/articles/v1.7/' . $nodes[0]->nid . ',' . $nodes[1]->nid));\n    $handler->setPath($nodes[0]->nid . ',' . $nodes[1]->nid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n\n    // Make sure that all the fields were mapped.\n    $this->assertNotNull($result[0]['body'], 'Body field is populated.');\n    $this->assertTrue($result[0]['tags'], 'Tags field is populated.');\n    $this->assertNotNull($result[0]['image'], 'Image field is not NULL.');\n  }\n\n  /**\n   * Test the field API formatter integration.\n   */\n  public function testFormatterIntegration() {\n    $resource_manager = restful()->getResourceManager();\n    $handler = $resource_manager->getPlugin('articles:1.5');\n\n    // Create node.\n    $text = 'Some body with long text';\n    $settings = array(\n      'type' => 'article',\n      'body' => array(\n        LANGUAGE_NONE => array(\n          array('value' => $text),\n        ),\n      ),\n    );\n    $node = $this->drupalCreateNode($settings);\n\n    // Field with no formatter.\n    $request = Request::create('api/articles/v1.5/' . $node->nid);\n    $handler->setRequest($request);\n    $handler->setPath($node->nid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    $this->assertEqual(trim(strip_tags($result[0]['body'])), $text, 'Raw value passed without a formatter.');\n\n    // Add formatter settings.\n    $field_definitions = $handler->getFieldDefinitions();\n    $display = array(\n      'type' => 'text_summary_or_trimmed',\n      'settings' => array(\n        'trim_length' => 10,\n      ),\n    );\n    /* @var \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityText $body */\n    $body = $field_definitions->get('body');\n    $body->setFormatter($display);\n    $field_definitions->set('body', $body);\n    $handler->setFieldDefinitions($field_definitions);\n    $resource_manager->clearPluginCache('articles:1.5');\n\n    $handler->setRequest($request);\n    $handler->setPath($node->nid);\n    $result = drupal_json_decode(restful()\n      ->getFormatterManager()\n      ->format($handler->process(), 'json'));\n    $result = $result['data'];\n    // Core's trim formatter also inclues the opening <p> tag in the calculation\n    // of number of chars.\n    $this->assertEqual($result[0]['body'], '<p>Some bo</p>', 'Value trimmed by formatter.');\n  }\n}\n"
  },
  {
    "path": "tests/modules/restful_node_access_test/restful_node_access_test.info",
    "content": "name = RESTful node access Test\ndescription = Helper module for testing the RESTful module with node access.\ncore = 7.x\ndependencies[] = restful\ndependencies[] = restful_test\nhidden = TRUE\n"
  },
  {
    "path": "tests/modules/restful_node_access_test/restful_node_access_test.module",
    "content": "<?php\n\n/**\n * @file\n * Helper module for testing the RESTful module with node access.\n */\n\n/**\n * Implements hook_node_grants().\n */\nfunction restful_node_access_test_node_grants($account, $op) {\n  if ($op != 'view') {\n    return NULL;\n  }\n\n  if (!$account->uid) {\n    return NULL;\n  }\n\n  $grants = array();\n  $grants['restful_test'][] = $account->uid;\n\n  return $grants;\n}\n\n/**\n * Implements hook_node_access_records().\n */\nfunction restful_node_access_test_node_access_records($node) {\n  $grants = array();\n  $grants[] = array(\n    'realm' => 'restful_test',\n    'gid' => $node->uid,\n    'grant_view' => 1,\n    'grant_update' => 0,\n    'grant_delete' => 0,\n    'priority' => 0,\n  );\n\n  return $grants;\n}\n"
  },
  {
    "path": "tests/modules/restful_test/restful_test.info",
    "content": "name = RESTful Test\ndescription = Helper module for testing the RESTful module.\ncore = 7.x\ndependencies[] = restful\ndependencies[] = restful_example\ndependencies[] = entity_feature\ndependencies[] = entityreference\nhidden = TRUE\n\nregistry_autoload[] = PSR-0\nregistry_autoload[] = PSR-4\n"
  },
  {
    "path": "tests/modules/restful_test/restful_test.install",
    "content": "<?php\n\n/**\n * @file\n * Install, update and uninstall functions for the entity_test module.\n */\n\n/**\n * Implements hook_install().\n */\nfunction restful_test_install() {\n  if (!db_field_exists('entity_test', 'uuid')) {\n    db_add_field('entity_test', 'uuid', array(\n      'type' => 'char',\n      'length' => 36,\n      'not null' => TRUE,\n      'default' => '',\n      'description' => 'The Universally Unique Identifier.',\n    ));\n    db_add_index('entity_test', 'uuid', array('uuid'));\n  }\n}\n\n/**\n * Implements hook_schema_alter().\n */\nfunction restful_test_schema_alter(&$schema = array()) {\n  $field = array(\n    'type' => 'char',\n    'length' => 36,\n    'not null' => TRUE,\n    'default' => '',\n    'description' => 'The Universally Unique Identifier.',\n  );\n  foreach (array('entity_test', 'restful_test_translatable_entity') as $table) {\n    $schema[$table]['fields']['uuid'] = $field;\n  }\n}\n\n/**\n * Implements hook_uninstall().\n */\nfunction restful_test_uninstall() {\n  variable_del('restful_test_alternative_id_error');\n  field_attach_delete_bundle('restful_test_translatable_entity', 'restful_test_translatable_entity');\n}\n\n/**\n * Implements hook_schema().\n */\nfunction restful_test_schema() {\n  $schema['restful_test_translatable_entity'] = array(\n    'description' => 'Stores restful_test_translatable_entity items.',\n    'fields' => array(\n      'pid' => array(\n        'type' => 'serial',\n        'not null' => TRUE,\n        'description' => 'Primary Key: Unique restful_test_translatable_entity item ID.',\n      ),\n      'name' => array(\n        'description' => 'The name of the restful_test_translatable_entity.',\n        'type' => 'varchar',\n        'length' => 32,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'uid' => array(\n        'type' => 'int',\n        'unsigned' => TRUE,\n        'not null' => FALSE,\n        'default' => NULL,\n        'description' => \"The {users}.uid of the associated user.\",\n      ),\n      'label' => array(\n        'type' => 'varchar',\n        'length' => 255,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'uuid' => array(\n        'type' => 'char',\n        'length' => 36,\n        'not null' => TRUE,\n        'default' => '',\n        'description' => 'The Universally Unique Identifier.',\n      ),\n    ),\n    'indexes' => array(\n      'uid' => array('uid'),\n      'uuid' => array('uuid'),\n    ),\n    'foreign keys' => array(\n      'uid' => array('users' => 'uid'),\n    ),\n    'primary key' => array('pid'),\n  );\n\n  // Defining table via hook_install() due to drupal_write_record().\n  $schema['restful_test_db_query'] = array(\n    'description' => 'Table for DbQuery testing.',\n    'fields' => array(\n      'id' => array(\n        'description' => 'The primary identifier for a record.',\n        'type' => 'serial',\n        'unsigned' => TRUE,\n        'not null' => TRUE,\n      ),\n      'str_field' => array(\n        'description' => 'String piece of data.',\n        'type' => 'varchar',\n        'length' => 32,\n        'not null' => TRUE,\n        'default' => '',\n      ),\n      'int_field' => array(\n        'description' => 'An int piece of data.',\n        'type' => 'int',\n        'not null' => TRUE,\n        'default' => 0,\n      ),\n      'serialized_field' => array(\n        'description' => 'An serialized piece of data.',\n        'type' => 'blob',\n        'serialize' => TRUE,\n      ),\n    ),\n    'primary key' => array('id'),\n  );\n\n  return $schema;\n}\n"
  },
  {
    "path": "tests/modules/restful_test/restful_test.module",
    "content": "<?php\n\n/**\n * @file\n * Helper module for testing the RESTful module.\n */\n\n/**\n * Flag a node to not be accessible.\n *\n * @param int $nid\n *   The node ID to deny access.\n */\nfunction restful_test_deny_access_node($nid) {\n  variable_set('restful_test_deny_access_node', $nid);\n}\n\n/**\n * Clear un-accessible node.\n */\nfunction restful_test_clear_access_node() {\n  variable_del('restful_test_deny_access_node');\n}\n\n/**\n * Implements hook_node_access().\n */\nfunction restful_test_node_access($node, $op, $account) {\n  if (!$nid = variable_get('restful_test_deny_access_node')) {\n    return NULL;\n  }\n\n  if ($op != 'view') {\n    return NULL;\n  }\n\n  if ($node->nid != $nid) {\n    return NULL;\n  }\n\n  // Deny access.\n  return NODE_ACCESS_DENY;\n}\n\n\n/**\n * Flag a field to not be accessible.\n *\n * @param string $field_name\n *   The field name. Defaults to \"body\".\n */\nfunction restful_test_deny_access_field($field_name = 'body') {\n  variable_set('restful_test_deny_access_field', $field_name);\n}\n\n/**\n * Clear un-accessible fields.\n */\nfunction restful_test_clear_access_field() {\n  variable_del('restful_test_deny_access_field');\n}\n\n/**\n * Implements hook_field_access().\n */\nfunction restful_test_field_access($op, $field, $entity_type, $entity, $account) {\n  if (!$field_name = variable_get('restful_test_deny_access_field')) {\n    return NULL;\n  }\n\n  if ($field_name == $field['field_name']) {\n    return FALSE;\n  }\n  return NULL;\n}\n\n/**\n * Helper function to add common fields.\n *\n * @param string $entity_type\n *   The entity type. Defautls to \"entity_test\".\n * @param string $bundle.\n *   The bundle name. Defaults to \"main\".\n *\n * @return int\n *   The vocabulary ID created.\n */\nfunction restful_test_add_fields($entity_type = 'entity_test', $bundle = 'main') {\n  // Text - single.\n  $field = array(\n    'field_name' => 'text_single',\n    'type' => 'text_long',\n    'entity_types' => array($entity_type),\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'text_single',\n    'bundle' => $bundle,\n    'entity_type' => $entity_type,\n    'label' => t('Text single'),\n    'settings' => array(\n      // No text processing\n      'text_processing' => 0,\n    ),\n  );\n  field_create_instance($instance);\n\n  // Text - single, with text processing.\n  $field = array(\n    'field_name' => 'text_single_processing',\n    'type' => 'text_long',\n    'entity_types' => array($entity_type),\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'text_single_processing',\n    'bundle' => $bundle,\n    'entity_type' => $entity_type,\n    'label' => t('Text single with text processing'),\n    'settings' => array(\n      'text_processing' => 1,\n    ),\n  );\n  field_create_instance($instance);\n\n  // Text - multiple.\n  $field = array(\n    'field_name' => 'text_multiple',\n    'type' => 'text_long',\n    'entity_types' => array($entity_type),\n    'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'text_multiple',\n    'bundle' => $bundle,\n    'entity_type' => $entity_type,\n    'label' => t('Text multiple'),\n    'settings' => array(\n      'text_processing' => 0,\n    ),\n  );\n  field_create_instance($instance);\n\n  // Text - multiple, with text processing.\n  $field = array(\n    'field_name' => 'text_multiple_processing',\n    'type' => 'text_long',\n    'entity_types' => array($entity_type),\n    'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'text_multiple_processing',\n    'bundle' => $bundle,\n    'entity_type' => $entity_type,\n    'label' => t('Text multiple with text processing'),\n    'settings' => array(\n      'text_processing' => 1,\n    ),\n  );\n  field_create_instance($instance);\n\n  // Entity reference - single.\n  $field = array(\n    'entity_types' => array($entity_type),\n    'settings' => array(\n      'handler' => 'base',\n      'target_type' => $entity_type,\n      'handler_settings' => array(\n      ),\n    ),\n    'field_name' => 'entity_reference_single',\n    'type' => 'entityreference',\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'entity_type' => $entity_type,\n    'field_name' => 'entity_reference_single',\n    'bundle' => $bundle,\n    'label' => t('Entity reference single'),\n  );\n\n  field_create_instance($instance);\n\n  // Entity reference - multiple.\n  $field = array(\n    'entity_types' => array($entity_type),\n    'settings' => array(\n      'handler' => 'base',\n      'target_type' => $entity_type,\n      'handler_settings' => array(\n      ),\n    ),\n    'field_name' => 'entity_reference_multiple',\n    'type' => 'entityreference',\n    'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'entity_type' => $entity_type,\n    'field_name' => 'entity_reference_multiple',\n    'bundle' => $bundle,\n    'label' => t('Entity reference multiple'),\n  );\n\n  field_create_instance($instance);\n\n  $vocabulary_id = restful_test_create_vocabulary_and_terms();\n\n  // Taxonomy term - single.\n  $field = array(\n    'field_name' => 'term_single',\n    'type' => 'taxonomy_term_reference',\n    'entity_types' => array($entity_type),\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'term_single',\n    'bundle' => $bundle,\n    'entity_type' => $entity_type,\n    'label' => t('Term reference single'),\n    'settings' => array(\n      'settings' => array(\n        'allowed_values' => array(\n          array(\n            'vocabulary' => $vocabulary_id,\n          ),\n        ),\n      ),\n    ),\n  );\n  field_create_instance($instance);\n\n  // Taxonomy term - multiple.\n  $field = array(\n    'field_name' => 'term_multiple',\n    'type' => 'taxonomy_term_reference',\n    'entity_types' => array($entity_type),\n    'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'term_multiple',\n    'bundle' => $bundle,\n    'entity_type' => $entity_type,\n    'label' => t('Term reference multiple'),\n    'settings' => array(\n      'settings' => array(\n        'allowed_values' => array(\n          array(\n            'vocabulary' => $vocabulary_id,\n          ),\n        ),\n      ),\n    ),\n  );\n  field_create_instance($instance);\n\n  // File field - single.\n  $field = array(\n    'field_name' => 'file_single',\n    'type' => 'file',\n    'settings' => array(),\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'file_single',\n    'entity_type' => $entity_type,\n    'label' => 'File single',\n    'bundle' => $bundle,\n  );\n  field_create_instance($instance);\n\n  // File field - multiple.\n  $field = array(\n    'field_name' => 'file_multiple',\n    'type' => 'file',\n    'settings' => array(),\n    'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'file_multiple',\n    'entity_type' => $entity_type,\n    'label' => 'File multiple',\n    'bundle' => $bundle,\n  );\n  field_create_instance($instance);\n\n  // Image field - single.\n  $field = array(\n    'field_name' => 'image_single',\n    'type' => 'image',\n    'settings' => array(),\n    'cardinality' => 1,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'image_single',\n    'entity_type' => $entity_type,\n    'label' => 'Image single',\n    'bundle' => $bundle,\n  );\n  field_create_instance($instance);\n\n  // Image field - multiple.\n  $field = array(\n    'field_name' => 'image_multiple',\n    'type' => 'image',\n    'settings' => array(),\n    'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n  );\n  field_create_field($field);\n\n  $instance = array(\n    'field_name' => 'image_multiple',\n    'entity_type' => $entity_type,\n    'label' => 'Image multiple',\n    'bundle' => $bundle,\n  );\n  field_create_instance($instance);\n\n  return $vocabulary_id;\n}\n\n\n/**\n * Helper function; Create a vocabulary and terms.\n *\n * @param string $machine_name\n *   The machine name of the vocabulary. Defaults to 'test_vocab'.\n * @param bool $create_vocab\n *   Determines if to create a vocabulary, or use an existing one.\n *\n * @return int\n *   The newly created vocabulary ID.\n */\nfunction restful_test_create_vocabulary_and_terms($machine_name = 'test_vocab', $create_vocab = TRUE) {\n  if ($create_vocab) {\n    $vocabulary = (object) array(\n      'name' => 'Tags test',\n      'description' => '',\n      'machine_name' => $machine_name,\n    );\n    taxonomy_vocabulary_save($vocabulary);\n  }\n  else {\n    $vocabulary = taxonomy_vocabulary_machine_name_load($machine_name);\n  }\n\n\n  $vid = $vocabulary->vid;\n\n  // Create three terms.\n  foreach (array(1, 2, 3) as $id) {\n    $values = array(\n      'name' => 'term' . $id,\n      'vid' => $vid,\n\n    );\n    $term = entity_create('taxonomy_term', $values);\n    taxonomy_term_save($term);\n  }\n\n  return $vid;\n}\n\n/**\n * Helper function; Create a node with taxonomy terms.\n *\n * @return object\n *   The saved node.\n */\nfunction restful_test_create_node_with_tags() {\n  $values = array('type' => 'article');\n  $node = entity_create('node', $values);\n\n  $vocabulary = taxonomy_vocabulary_machine_name_load('tags');\n\n  // Create a random number of tags for the created node.\n  for ($index = 0; $index < mt_rand(1, 10); $index++) {\n    $term = (object) array(\n      'vid' => $vocabulary->vid,\n      'name' => 'term ' . $vocabulary->vid . '::' . $index,\n    );\n    taxonomy_term_save($term);\n    $terms[] = $term;\n    $node->field_tags[LANGUAGE_NONE][$index]['tid'] = $term->tid;\n  }\n  node_save($node);\n\n  return $node;\n}\n\n/**\n * Implements hook_entity_info().\n */\nfunction restful_test_entity_info() {\n  return array(\n    'restful_test_translatable_entity' => array(\n      'label' => t('Translatable Test Entity'),\n      'plural label' => t('Translatable Test Entities'),\n      'description' => t('An entity type used by the RESTful tests.'),\n      'entity class' => 'Entity',\n      'controller class' => 'EntityAPIController',\n      'base table' => 'restful_test_translatable_entity',\n      'fieldable' => TRUE,\n      'entity keys' => array(\n        'id' => 'pid',\n        'bundle' => 'name',\n        'label' => 'label',\n        'uuid' => 'uuid',\n      ),\n      // Make use the class' label() and uri() implementation by default.\n      'label callback' => 'entity_class_label',\n      'uri callback' => 'entity_class_uri',\n      'bundles' => array(\n        'restful_test_translatable_entity' => array(\n          'label' => 'Translatable Test Entity',\n        ),\n      ),\n      'bundle keys' => array(\n        'bundle' => 'name',\n      ),\n      'module' => 'restful_test',\n      'translation' => array(\n        'locale' => TRUE,\n      ),\n      'uuid' => TRUE,\n    ),\n  );\n}\n\n/**\n * Implements hook_restful_resource_alter().\n *\n * Decorate an existing resource with other services (e.g. rate limit and render\n * cache).\n */\nfunction restful_test_restful_resource_alter(\\Drupal\\restful\\Plugin\\resource\\ResourceInterface &$resource) {\n  // Disable the Files Upload resource based on the settings variable.\n  if ($resource->getResourceMachineName() == 'files_upload_test') {\n    variable_get('restful_file_upload', FALSE) ? $resource->enable() : $resource->disable();\n  }\n}\n\n/**\n * Implements hook_entity_info_alter().\n */\nfunction restful_test_entity_info_alter(&$entity_info) {\n  $entity_info['entity_test']['uuid'] = TRUE;\n  $entity_info['entity_test']['entity keys']['uuid'] = 'uuid';\n}\n\n/**\n * Implements hook_entity_property_info_alter().\n */\nfunction restful_test_entity_property_info_alter(&$info) {\n  $entity_types = array('entity_test', 'restful_test_translatable_entity');\n  foreach ($entity_types as $entity_type) {\n    $entity_info = entity_get_info($entity_type);\n    if (isset($entity_info['uuid']) && $entity_info['uuid'] == TRUE\n      && !empty($entity_info['entity keys']['uuid'])\n      && empty($info[$entity_type]['properties'][$entity_info['entity keys']['uuid']])) {\n      $info[$entity_type]['properties'][$entity_info['entity keys']['uuid']] = array(\n        'label' => t('UUID'),\n        'type' => 'text',\n        'description' => t('The universally unique ID.'),\n        'schema field' => $entity_info['entity keys']['uuid'],\n      );\n      if (!empty($entity_info['entity keys']['revision uuid'])\n        && empty($info[$entity_type]['properties'][$entity_info['entity keys']['revision uuid']])) {\n        $info[$entity_type]['properties'][$entity_info['entity keys']['revision uuid']] = array(\n          'label' => t('Revision UUID'),\n          'type' => 'text',\n          'description' => t(\"The revision's universally unique ID.\"),\n          'schema field' => $entity_info['entity keys']['revision uuid'],\n        );\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/DataProvider/DataProviderFileTest.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\DataProvider\\DataProviderFileTest.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\DataProvider;\n\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderFile;\n\nclass DataProviderFileTest extends DataProviderFile {\n\n  /**\n   * Helper function that checks if a file was uploaded via a POST request.\n   *\n   * @param string $filename\n   *   The name of the file.\n   *\n   * @return bool\n   *   TRUE if the file is uploaded. FALSE otherwise.\n   */\n  protected static function isUploadedFile($filename) {\n    return variable_get('restful_insecure_uploaded_flag', FALSE) || is_uploaded_file($filename);\n  }\n\n  /**\n   * Helper function that moves an uploaded file.\n   *\n   * @param string $filename\n   *   The path of the file to move.\n   * @param string $uri\n   *   The path where to move the file.\n   *\n   * @return bool\n   *   TRUE if the file was moved. FALSE otherwise.\n   */\n  protected static function moveUploadedFile($filename, $uri) {\n    if (drupal_move_uploaded_file($filename, $uri)) {\n      return TRUE;\n    }\n    return variable_get('restful_insecure_uploaded_flag', FALSE) && (bool) file_unmanaged_move($filename, $uri);\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/db_query_test/v1/DbQueryTest__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\db_query_test\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceDbQuery;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class DbQueryTest__1_0\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"db_query_test:1.0\",\n *   resource = \"db_query_test\",\n *   label = \"DB Query Test\",\n *   description = \"Expose the test table.\",\n *   dataProvider = {\n *     \"tableName\": \"restful_test_db_query\",\n *     \"idColumn\": \"id\",\n *     \"primary\": \"id\",\n *     \"idField\": \"id\",\n *   },\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   renderCache = {\n *     \"render\": true\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass DbQueryTest__1_0 extends ResourceDbQuery implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $fields = array();\n\n    $fields['id'] = array('property' => 'id');\n    $fields['string'] = array('property' => 'str_field');\n    $fields['integer'] = array('property' => 'int_field');\n    $fields['serialized'] = array('property' => 'serialized_field');\n\n    return $fields;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/EntityTests__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\EntityTests__1_0.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class EntityTests__1_0\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"entity_tests:1.0\",\n *   resource = \"entity_tests\",\n *   label = \"Entity tests\",\n *   description = \"Export the entity test with multiple bundles.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"test\",\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass EntityTests__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['main_bundle'] = array(\n      'property' => 'pid',\n      'class' => '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityReference',\n      'resource' => array(\n        'name' => 'main',\n        'majorVersion' => 1,\n        'minorVersion' => 0,\n      ),\n    );\n    $public_fields['tests_bundle'] = array(\n      'property' => 'pid',\n      'class' => '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldEntityReference',\n      'resource' => array(\n        'name' => 'tests',\n        'majorVersion' => 1,\n        'minorVersion' => 0,\n      ),\n    );\n\n    return $public_fields;\n  }\n\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_0.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_0\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.0\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Main__1_0 extends ResourceEntity implements ResourceInterface {}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_1.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_1.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_1\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.1\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 1\n * )\n */\nclass Main__1_1 extends Main__1_0 implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['text_single'] = array(\n      'property' => 'text_single',\n    );\n\n    $public_fields['text_multiple'] = array(\n      'property' => 'text_multiple',\n      'discovery' => array(\n        'info' => array(\n          'label' => t('Text multiple'),\n          'description' => t('This field holds different text inputs.'),\n        ),\n        'data' => array(\n          'type' => 'string',\n          'cardinality' => FIELD_CARDINALITY_UNLIMITED,\n        ),\n        'form_element' => array(\n          'type' => 'textfield',\n          'size' => 255,\n          'placeholder' => t('This is helpful.'),\n        ),\n      ),\n    );\n\n    $public_fields['text_single_processing'] = array(\n      'property' => 'text_single_processing',\n      'sub_property' => 'value',\n    );\n\n    $public_fields['text_multiple_processing'] = array(\n      'property' => 'text_multiple_processing',\n      'sub_property' => 'value',\n    );\n\n    $public_fields['entity_reference_single'] = array(\n      'property' => 'entity_reference_single',\n      'wrapper_method' => 'getIdentifier',\n    );\n\n    $public_fields['entity_reference_multiple'] = array(\n      'property' => 'entity_reference_multiple',\n      'wrapper_method' => 'getIdentifier',\n    );\n\n    // Single entity reference field with \"resource\".\n    $public_fields['entity_reference_single_resource'] = array(\n      'property' => 'entity_reference_single',\n      'resource' => array(\n        'name' => 'main',\n        'majorVersion' => 1,\n        'minorVersion' => 1,\n      ),\n    );\n\n    // Multiple entity reference field with \"resource\".\n    $public_fields['entity_reference_multiple_resource'] = array(\n      'property' => 'entity_reference_multiple',\n      'resource' => array(\n        'name' => 'main',\n        'majorVersion' => 1,\n        'minorVersion' => 1,\n      ),\n    );\n\n    $public_fields['term_single'] = array(\n      'property' => 'term_single',\n      'sub_property' => 'tid',\n    );\n\n    $public_fields['term_multiple'] = array(\n      'property' => 'term_multiple',\n      'sub_property' => 'tid',\n    );\n\n    $public_fields['file_single'] = array(\n      'property' => 'file_single',\n      'process_callbacks' => array(\n        array($this, 'getFilesId'),\n      ),\n    );\n\n    $public_fields['file_multiple'] = array(\n      'property' => 'file_multiple',\n      'process_callbacks' => array(\n        array($this, 'getFilesId'),\n      ),\n    );\n\n    $public_fields['image_single'] = array(\n      'property' => 'image_single',\n      'process_callbacks' => array(\n        array($this, 'getFilesId'),\n      ),\n    );\n\n    $public_fields['image_multiple'] = array(\n      'property' => 'image_multiple',\n      'process_callbacks' => array(\n        array($this, 'getFilesId'),\n      ),\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * Return the files ID from the multiple files array.\n   *\n   * Since by default Entity API does not allow to get the file ID, we extract\n   * it ourself in this preprocess callback.\n   *\n   * @param array $value\n   *   Array of files array as retrieved by the wrapper.\n   *\n   * @return int\n   *   Array with file IDs.\n   */\n  public function getFilesId(array $value) {\n    if (ResourceFieldBase::isArrayNumeric($value)) {\n      $return = array();\n      foreach ($value as $file_array) {\n        $return[] = $this->getFilesId($file_array);\n      }\n      return $return;\n    }\n    return empty($value['fid']) ? NULL : $value['fid'];\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_2.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_2.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_2\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.2\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 2\n * )\n */\nclass Main__1_2 extends Main__1_0 implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['callback'] = array(\n      'callback' => array($this, 'callback'),\n    );\n\n    $public_fields['process_callback_from_callback'] = array(\n      'callback' => array($this, 'callback'),\n      'process_callbacks' => array(\n        array($this, 'processCallbackFromCallback'),\n      ),\n    );\n\n    $public_fields['process_callback_from_value'] = array(\n      'wrapper_method' => 'getIdentifier',\n      'wrapper_method_on_entity' => TRUE,\n      'process_callbacks' => array(\n        array($this, 'processCallbackFromValue'),\n      ),\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * Return a computed value.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter.\n   *\n   * @return mixed\n   *   The output for the computed field.\n   */\n  public function callback(DataInterpreterInterface $interpreter) {\n    return 'callback';\n  }\n\n  /**\n   * Process a computed value.\n   */\n  public function processCallbackFromCallback($value) {\n    return $value . ' processed from callback';\n  }\n\n  /**\n   * Process a property value.\n   */\n  public function processCallbackFromValue($value) {\n    return $value . ' processed from value';\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_3.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_3.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_3\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.3\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 3\n * )\n */\nclass Main__1_3 extends Main__1_0 implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['callback'] = array(\n      'callback' => array($this, 'invalidCallback'),\n    );\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_4.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_4.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_4\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.4\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 4\n * )\n */\nclass Main__1_4 extends Main__1_0 implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['process_callbacks'] = array(\n      'wrapper_method' => 'label',\n      'wrapper_method_on_entity' => TRUE,\n      'process_callbacks' => array(\n        array($this, 'invalidProcessCallback'),\n      ),\n    );\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_5.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_5.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_5\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.5\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationTypes = {\n *     \"basic_auth\",\n *     \"cookie\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 5\n * )\n */\nclass Main__1_5 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['process_callbacks'] = array(\n      'wrapper_method' => 'label',\n      'wrapper_method_on_entity' => TRUE,\n      'process_callbacks' => array(\n        array($this, 'invalidProcessCallback'),\n      ),\n    );\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_6.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_6.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_6\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.6\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationTypes = {\n *     \"basic_auth\",\n *     \"cookie\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 6\n * )\n */\nclass Main__1_6 extends Main__1_1 implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['entity_reference_single_resource']['resource']['name'] = 'test_articles';\n    $public_fields['entity_reference_multiple_resource']['resource']['name'] = 'test_articles';\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_7.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_7.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Main__1_7\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.7\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationTypes = {\n *     \"basic_auth\",\n *     \"cookie\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *     \"idField\": \"uuid\"\n *   },\n *   majorVersion = 1,\n *   minorVersion = 7\n * )\n */\nclass Main__1_7 extends Main__1_0 implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n    $public_fields['uuid'] = array(\n      'property' => 'uuid',\n      'methods' => array(),\n    );\n\n    // Single entity reference field without \"resource\".\n    $public_fields['entity_reference_single'] = array(\n      'property' => 'entity_reference_single',\n      'referencedIdProperty' => 'uuid',\n    );\n\n    // Single entity reference field with \"resource\" that loads by uuid.\n    $public_fields['entity_reference_resource'] = array(\n      'property' => 'entity_reference_single',\n      'referencedIdProperty' => 'uuid',\n      'resource' => array(\n        'name' => 'main',\n        'majorVersion' => 1,\n        'minorVersion' => 7,\n      ),\n    );\n\n    // Multiple entity reference field without \"resource\".\n    $public_fields['entity_reference_multiple'] = array(\n      'property' => 'entity_reference_multiple',\n      'referencedIdProperty' => 'uuid',\n    );\n\n    $public_fields['term_single'] = array(\n      'property' => 'term_single',\n      'referencedIdProperty' => 'uuid',\n    );\n\n    $public_fields['term_multiple'] = array(\n      'property' => 'term_multiple',\n      'referencedIdProperty' => 'uuid',\n    );\n\n    $public_fields['file_single'] = array(\n      'property' => 'file_single',\n      'class' => '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldFileEntityReference',\n      'referencedIdProperty' => 'uuid',\n    );\n\n    $public_fields['file_multiple'] = array(\n      'property' => 'file_multiple',\n      'class' => '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldFileEntityReference',\n      'referencedIdProperty' => 'uuid',\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function processPublicFields(array $field_definitions) {\n    if (variable_get('restful_test_alternative_id_error', FALSE)) {\n      // Single entity reference field with \"resource\" that does not load by\n      // uuid.\n      $field_definitions['entity_reference_resource_error'] = array(\n        'property' => 'entity_reference_single',\n        'referencedIdProperty' => 'uuid',\n        'resource' => array(\n          'name' => 'main',\n          'majorVersion' => 1,\n          'minorVersion' => 6,\n        ),\n      );\n    }\n    return parent::processPublicFields($field_definitions);\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/main/v1/Main__1_8.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_8.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\n\n/**\n * Class Main__1_8.\n *\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"main:1.8\",\n *   resource = \"main\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"main\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 8\n * )\n */\nclass Main__1_8 extends Main__1_0 {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $class = get_class($this);\n    $public_fields['random_rel'] = array(\n      'callback' => $class . '::randomRelationship',\n      'class' => '\\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldReference',\n      'resource' => array(\n        'name' => 'db_query_test',\n        'majorVersion' => 1,\n        'minorVersion' => 0,\n      ),\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * Returns a random relationship.\n   *\n   * This serves as an example of a use case for the generic relationship.\n   *\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter.\n   *\n   * @return mixed\n   *   The embeddable result.\n   */\n  public static function randomRelationship(DataInterpreterInterface $interpreter) {\n    /* @var \\Drupal\\restful\\Plugin\\resource\\ResourceInterface $handler */\n    $handler = restful()->getResourceManager()->getPlugin('db_query_test:1.0');\n    // This simbolizes some complex logic that gets a rendered resource.\n    $id = static::complexCalculation();\n    return $handler->getDataProvider()->view($id);\n  }\n\n  /**\n   * Do a complex calculation.\n   *\n   * @return int\n   *   The ID of the db_query_test.\n   */\n  protected static function complexCalculation() {\n    return 1;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/entity_test/tests/Tests__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\entity_test\\tests\\Tests__1_0.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\entity_test\\tests;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class Tests__1_0\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"tests:1.0\",\n *   resource = \"tests\",\n *   label = \"Tests\",\n *   description = \"Export the entity test 'tests' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"entity_test\",\n *     \"bundles\": {\n *       \"test\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass Tests__1_0 extends ResourceEntity implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    return array(\n      'type' => array(\n        'wrapper_method' => 'getBundle',\n        'wrapper_method_on_entity' => TRUE,\n      ),\n    ) + parent::publicFields();\n  }\n\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/file/file_upload_test/v1/FilesUploadTest__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\file\\file_upload_test\\v1\\FilesUploadTest__1_0.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\file\\file_upload_test\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\FilesUpload__1_0;\n\n/**\n * Class FilesUploadTest__1_0\n * @package Drupal\\restful_example\\Plugin\\Resource\n *\n * @Resource(\n *   name = \"files_upload_test:1.0\",\n *   resource = \"files_upload_test\",\n *   label = \"File upload for testing\",\n *   description = \"A file upload wrapped with RESTful.\",\n *   authenticationTypes = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"file\",\n *     \"options\": {\n *       \"scheme\": \"public\"\n *     }\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass FilesUploadTest__1_0 extends FilesUpload__1_0 {\n\n  /**\n   * Data provider class.\n   *\n   * @return string\n   *   The name of the class of the provider factory.\n   */\n  protected function dataProviderClassName() {\n    return '\\Drupal\\restful_test\\Plugin\\resource\\DataProvider\\DataProviderFileTest';\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/node/test_article/v1/TestArticles__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1\\TestArticles__1_0.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class TestArticles__1_0\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"test_articles:1.0\",\n *   resource = \"test_articles\",\n *   label = \"Test Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationTypes = {\n *     \"basic_auth\",\n *     \"cookie\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass TestArticles__1_0 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    if (!module_exists('entity_validator')) {\n      return $public_fields;\n    }\n    $public_fields['title'] = $public_fields['label'];\n    $public_fields['body'] = array(\n      'property' => 'body',\n      'sub_property' => 'value',\n    );\n\n    return $public_fields;\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function processPublicFields(array $field_definitions) {\n    $field_definitions = parent::processPublicFields($field_definitions);\n    if (!$altered_public_name = variable_get('restful_test_revoke_public_field_access')) {\n      return $field_definitions;\n    }\n    foreach ($field_definitions as $public_name => &$field_definition) {\n      if ($public_name != $altered_public_name) {\n        continue;\n      }\n      $field_definition['access_callbacks'] = array(array($this, 'publicFieldAccessFalse'));\n    }\n    return $field_definitions;\n  }\n\n  /**\n   * An access callback that returns TRUE if title is \"access\". Otherwise FALSE.\n   *\n   * @param string $op\n   *   The operation that access should be checked for. Can be \"view\" or \"edit\".\n   *   Defaults to \"edit\".\n   * @param ResourceFieldInterface $resource_field\n   *   The resource field to check access upon.\n   * @param DataInterpreterInterface $interpreter\n   *   The data interpreter.\n   *\n   * @return string\n   *   \"Allow\" or \"Deny\" if user has access to the property.\n   */\n  public static function publicFieldAccessFalse($op, ResourceFieldInterface $resource_field, DataInterpreterInterface $interpreter) {\n    return $interpreter->getWrapper()->label() == 'access' ? \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase::ACCESS_ALLOW : \\Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldBase::ACCESS_DENY;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/node/test_article/v1/TestArticles__1_1.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1\\TestArticles__1_1.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\n\n/**\n * Class TestArticles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"test_articles:1.1\",\n *   resource = \"test_articles\",\n *   label = \"Test Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationTypes = {\n *     \"basic_auth\",\n *     \"cookie\"\n *   },\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *     \"sort\": {\n *       \"label\": \"ASC\",\n *       \"id\": \"DESC\"\n *     },\n *   },\n *   renderCache = {\n *     \"render\": TRUE\n *   },\n *   majorVersion = 1,\n *   minorVersion = 1\n * )\n */\nclass TestArticles__1_1 extends TestArticles__1_0 implements ResourceInterface {\n  // TODO: Document a changelog from defaultSortInfo to the annotation for the data provider.\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/node/test_article/v1/TestArticles__1_2.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1\\TestArticles__1_2.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class TestArticles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"test_articles:1.2\",\n *   resource = \"test_articles\",\n *   label = \"Test Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationTypes = {\n *     \"basic_auth\",\n *     \"cookie\"\n *   },\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 2\n * )\n */\nclass TestArticles__1_2 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * Overrides ResourceEntity::publicFields().\n   */\n  public function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['body'] = array(\n      'property' => 'body',\n      'sub_property' => 'value',\n    );\n\n    // By checking that the field exists, we allow re-using this class on\n    // different tests, where different fields exist.\n    if (field_info_field('entity_reference_single')) {\n      $public_fields['entity_reference_single'] = array(\n        'property' => 'entity_reference_single',\n        'resource' => array(\n          'name' => 'test_articles',\n          'majorVersion' => 1,\n          'minorVersion' => 2,\n        ),\n      );\n    }\n\n    if (field_info_field('entity_reference_multiple')) {\n      $public_fields['entity_reference_multiple'] = array(\n        'property' => 'entity_reference_multiple',\n        'resource' => array(\n          'name' => 'test_articles',\n          'majorVersion' => 1,\n          'minorVersion' => 2,\n        ),\n      );\n    }\n\n    if (field_info_field('integer_single')) {\n      $public_fields['integer_single'] = array(\n        'property' => 'integer_single',\n      );\n    }\n\n    if (field_info_field('integer_multiple')) {\n      $public_fields['integer_multiple'] = array(\n        'property' => 'integer_multiple',\n      );\n    }\n\n    if (variable_get('restful_test_reference_simple')) {\n      $public_fields['user'] = array(\n        'property' => 'author',\n      );\n\n      if (variable_get('restful_test_reference_resource')) {\n        $public_fields['user']['resource'] = array(\n          'name' => 'users',\n          'majorVersion' => 1,\n          'minorVersion' => 0,\n        );\n      }\n    }\n\n    return $public_fields;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/node/test_article/v1/TestArticles__1_3.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1\\TestArticles__1_3.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class TestArticles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"test_articles:1.3\",\n *   resource = \"test_articles\",\n *   label = \"Test Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 3\n * )\n */\nclass TestArticles__1_3 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function controllersInfo() {\n    $info = parent::controllersInfo();\n    $info['^.*$'][RequestInterface::METHOD_GET] = array(\n      'callback' => 'view',\n      'access callback' => 'accessViewEntityFalse',\n    );\n    $info['^.*$'][RequestInterface::METHOD_HEAD] = array(\n      'callback' => 'view',\n      'access callback' => 'accessViewEntityTrue',\n    );\n    return $info;\n  }\n\n  /**\n   * Custom access callback for the GET method.\n   *\n   * @return bool\n   *   TRUE for access granted, FALSE otherwise.\n   */\n  public function accessViewEntityFalse() {\n    return FALSE;\n  }\n\n  /**\n   * Custom access callback for the HEAD method.\n   *\n   * @return bool\n   *   TRUE for access granted, FALSE otherwise.\n   */\n  public function accessViewEntityTrue() {\n    return TRUE;\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/node/test_article/v1/TestArticles__1_4.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1\\TestArticles__1_4.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\node\\test_article\\v1;\n\nuse Drupal\\restful\\Http\\RequestInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful\\Plugin\\resource\\ResourceNode;\n\n/**\n * Class TestArticles\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"test_articles:1.4\",\n *   resource = \"test_articles\",\n *   label = \"Test Articles\",\n *   description = \"Export the article content type.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"node\",\n *     \"bundles\": {\n *       \"article\"\n *     },\n *   },\n *   allowOrigin = \"*\",\n *   formatter = \"hal_xml\",\n *   majorVersion = 1,\n *   minorVersion = 4\n * )\n */\nclass TestArticles__1_4 extends ResourceNode implements ResourceInterface {\n\n  /**\n   * {@inheritdoc}\n   */\n  public function controllersInfo() {\n    return array(\n      '' => array(\n        RequestInterface::METHOD_HEAD => 'index',\n        RequestInterface::METHOD_OPTIONS => 'discover',\n      ),\n      '^(\\d+,)*\\d+$' => array(\n        RequestInterface::METHOD_PATCH => 'update',\n        RequestInterface::METHOD_DELETE => 'remove',\n        RequestInterface::METHOD_OPTIONS => 'discover',\n      ),\n    );\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/restful_test_translatable_entity/v1/RestfulTestTranslatableEntityResource__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\restful_test_translatable_entity\\v1\\RestfulTestTranslatableEntityResource__1_0.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\restful_test_translatable_entity\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\ResourceInterface;\nuse Drupal\\restful_test\\Plugin\\resource\\entity_test\\main\\v1\\Main__1_0;\n\n/**\n * Class RestfulTestTranslatableEntityResource__1_0\n * @package Drupal\\restful_test\\Plugin\\resource\n *\n * @Resource(\n *   name = \"restful_test_translatable_entity:1.0\",\n *   resource = \"restful_test_translatable_entity\",\n *   label = \"Main\",\n *   description = \"Export the entity test 'main' bundle.\",\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"restful_test_translatable_entity\",\n *     \"bundles\": {\n *       \"restful_test_translatable_entity\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass RestfulTestTranslatableEntityResource__1_0 extends Main__1_0 implements ResourceInterface {\n\n  /**\n   * Overrides Main__1_0::publicFields().\n   */\n  protected function publicFields() {\n    $public_fields = parent::publicFields();\n\n    $public_fields['text_single'] = array(\n      'property' => 'text_single',\n    );\n\n    $public_fields['text_multiple'] = array(\n      'property' => 'text_multiple',\n    );\n\n    return $public_fields;\n  }\n\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/taxonomy_term/v1/DataProviderTaxonomyTerm.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\taxonomy_term\\v1\\DataProviderTaxonomyTerm.\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\taxonomy_term\\v1;\n\nuse Drupal\\restful\\Plugin\\resource\\DataInterpreter\\DataInterpreterInterface;\nuse Drupal\\restful\\Plugin\\resource\\DataProvider\\DataProviderTaxonomyTerm as DataProviderTaxonomyTermOriginal;\nuse Drupal\\restful\\Plugin\\resource\\Field\\ResourceFieldInterface;\n\nclass DataProviderTaxonomyTerm extends DataProviderTaxonomyTermOriginal {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function checkEntityAccess($op, $entity_type, $entity) {\n    $account = $this->getAccount();\n    return user_access('create article content', $account);\n  }\n\n  /**\n   * {@inheritdoc}\n   */\n  protected static function checkPropertyAccess(ResourceFieldInterface $resource_field, $op, DataInterpreterInterface $interpreter) {\n    $term = $interpreter->getWrapper()->value();\n    if ($resource_field->getProperty() == 'name' && empty($term->tid) && $op == 'edit') {\n      return TRUE;\n    }\n    return parent::checkPropertyAccess($resource_field, $op, $interpreter);\n  }\n\n}\n"
  },
  {
    "path": "tests/modules/restful_test/src/Plugin/resource/taxonomy_term/v1/TestTags__1_0.php",
    "content": "<?php\n\n/**\n * @file\n * Contains \\Drupal\\restful_test\\Plugin\\resource\\taxonomy_term\\v1\\TestTags__1_0;\n */\n\nnamespace Drupal\\restful_test\\Plugin\\resource\\taxonomy_term\\v1;\nuse Drupal\\restful\\Plugin\\resource\\ResourceEntity;\n\n/**\n * Class TestTags\n * @package Drupal\\restful\\Plugin\\resource\n *\n * @Resource(\n *   name = \"test_tags:1.0\",\n *   resource = \"test_tags\",\n *   label = \"Test Tags\",\n *   description = \"Export the tag taxonomy terms.\",\n *   authenticationTypes = TRUE,\n *   authenticationOptional = TRUE,\n *   dataProvider = {\n *     \"entityType\": \"taxonomy_term\",\n *     \"bundles\": {\n *       \"tags\"\n *     },\n *   },\n *   majorVersion = 1,\n *   minorVersion = 0\n * )\n */\nclass TestTags__1_0 extends ResourceEntity {\n\n  /**\n   * {@inheritdoc}\n   */\n  protected function dataProviderClassName() {\n    return '\\Drupal\\restful_test\\Plugin\\resource\\taxonomy_term\\v1\\DataProviderTaxonomyTerm';\n  }\n\n}\n"
  }
]