commit 689d5482b745a62f495f1292a3525f4482b82251 Author: Klaus Purer Date: Tue Oct 30 11:48:02 2012 +0100 Update. diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php index 48d9d0d..633e225 100644 --- a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php +++ b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceBase.php @@ -8,47 +8,13 @@ namespace Drupal\rest\Plugin; use Drupal\Component\Plugin\PluginBase; -use Drupal\rest\Plugin\ResourceInterface; -use Drupal\rest\ResourceException; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; /** * Common base class for resource plugins. */ -abstract class ResourceBase extends PluginBase implements ResourceInterface { - - /** - * Implements ResourceInterface::create(). - */ - public function create($format, $data) { - // Forbid this operation per default. - throw new ResourceException('Access Denied', 403); - } - - /** - * Implements ResourceInterface::create(). - */ - public function read($id, $format) { - // Forbid this operation per default. - throw new ResourceException('Access Denied', 403); - } - - /** - * Implements ResourceInterface::create(). - */ - public function update($format, $id, $data) { - // Forbid this operation per default. - throw new ResourceException('Access Denied', 403); - } - - /** - * Implements ResourceInterface::create(). - */ - public function delete($id) { - // Forbid this operation per default. - throw new ResourceException('Access Denied', 403); - } +abstract class ResourceBase extends PluginBase { /** * Temporary helper for building permissions. @@ -56,10 +22,15 @@ public function delete($id) { public function permissions() { $permissions = array(); $definition = $this->getDefinition(); - foreach ($this->endpoints() as $endpoint => $method) { - $permissions["restful $endpoint $this->plugin_id"] = array( - 'title' => t(drupal_ucfirst($endpoint) . ' resource @label', array('@label' => $definition['label'])), - ); + foreach ($this->requestMethods() as $method) { + $lowered_method = strtolower($method); + // Only expose permissions where the HTTP request method exists on the + // plugin. + if (method_exists($this, $lowered_method)) { + $permissions["restful $lowered_method $this->plugin_id"] = array( + 'title' => t('Access @method on resource %label', array('@method' => $method, '%label' => $definition['label'])), + ); + } } return $permissions; } @@ -73,32 +44,47 @@ public function permissions() { public function routes() { $collection = new RouteCollection(); - foreach ($this->endpoints() as $endpoint => $method) { - $prefix = strtr($this->plugin_id, ':', '/'); - $route = new Route("/$prefix/{id}", array( - '_controller' => 'Drupal\rest\RequestHandler::' . $endpoint, - 'plugin' => $this->plugin_id, - ), array( - '_method' => $method, - 'format' => 'application/ld+json', - )); + $methods = $this->requestMethods(); + foreach ($methods as $method) { + // Only expose routes where the HTTP request method exists on the plugin. + if (method_exists($this, strtolower($method))) { + $prefix = strtr($this->plugin_id, ':', '/'); + $route = new Route("/$prefix/{id}", array( + '_controller' => 'Drupal\rest\RequestHandler::handle', + 'plugin' => $this->plugin_id, + ), array( + '_method' => $method, + 'format' => 'application/ld+json', + )); - $name = strtr($this->plugin_id, ':', '.'); - $collection->add("$name.$endpoint", $route); + $name = strtr($this->plugin_id, ':', '.'); + $collection->add("$name.$method", $route); + } } return $collection; } /** - * Temporary helper for retrieving supported endpoints. + * Provides predefined HTTP request methods. + * + * Plugins can override this method to provide additional custom request + * methods. + * + * @return array + * The list of allowed HTTP request method strings. */ - protected function endpoints() { - return array( - 'create' => 'POST', - 'read' => 'GET', - 'update' => 'PUT', - 'delete' => 'DELETE', - ); + protected function requestMethods() { + return drupal_map_assoc(array( + 'HEAD', + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'TRACE', + 'OPTIONS', + 'CONNECT', + 'PATCH', + )); } } diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceInterface.php b/core/modules/rest/lib/Drupal/rest/Plugin/ResourceInterface.php deleted file mode 100644 index 2866474..0000000 --- a/core/modules/rest/lib/Drupal/rest/Plugin/ResourceInterface.php +++ /dev/null @@ -1,75 +0,0 @@ -getDefinition(); @@ -35,11 +44,4 @@ public function delete($id) { } throw new ResourceException(t('Entity with ID @id not found', array('@id' => $id)), 404); } - - /** - * Implements ResourceInterface::access(). - */ - public function access($resource_type, $operation, $id) { - return TRUE; - } } diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/WatchdogResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/WatchdogResource.php index db94747..096c91b 100644 --- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/WatchdogResource.php +++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/WatchdogResource.php @@ -7,9 +7,10 @@ namespace Drupal\rest\Plugin\rest\resource; -use Symfony\Component\HttpFoundation\Response; +use Drupal\rest\ResourceException; use Drupal\rest\Plugin\ResourceBase; use Drupal\Core\Annotation\Plugin; +use Symfony\Component\HttpFoundation\Response; /** * Provides a resource for database watchdog log entries. @@ -33,9 +34,16 @@ public function routes() { } /** - * Implements ResourceInterface::read(). + * Responds to GET requests. + * + * Returns a watchdog log entry for the specified ID. + * + * @return \Symfony\Component\HttpFoundation\Response + * The response object. + * + * @throws \Drupal\rest\ResourceException */ - public function read($id = NULL, $format = 'application/ld+json') { + public function get($id = NULL) { if ($id) { $result = db_select('watchdog', 'w') ->condition('wid', $id) @@ -49,11 +57,4 @@ public function read($id = NULL, $format = 'application/ld+json') { return new Response(drupal_json_encode($result[0]), 200, array('Content-Type' => 'application/json')); } } - - /** - * Implements ResourceInterface::access(). - */ - public function access($resource_type, $operation, $id) { - return TRUE; - } } diff --git a/core/modules/rest/lib/Drupal/rest/RequestHandler.php b/core/modules/rest/lib/Drupal/rest/RequestHandler.php index d965e3d..960a703 100644 --- a/core/modules/rest/lib/Drupal/rest/RequestHandler.php +++ b/core/modules/rest/lib/Drupal/rest/RequestHandler.php @@ -8,6 +8,7 @@ namespace Drupal\rest; use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** @@ -16,44 +17,23 @@ class RequestHandler extends ContainerAware { /** - * Handles a web API read request. + * Handles a web API request. * * @param string $plugin * The resource type plugin. + * @param Symfony\Component\HttpFoundation\Request $request + * The HTTP request object. * @param mixed $id * The resource ID. */ - public function read($plugin, $id) { - if (user_access("restful read $plugin")) { - $plugin = $this->container + public function handle($plugin, Request $request, $id = NULL) { + $method = strtolower($request->getMethod()); + if (user_access("restful $method $plugin")) { + $resource = $this->container ->get('plugin.manager.rest') ->createInstance($plugin); try { - // @todo: replace hard coded format here. - return $plugin->read($id, 'application/ld+json'); - } - catch (ResourceException $e) { - return new Response($e->getMessage(), $e->getCode(), $e->getHeaders()); - } - } - return new Response('Access Denied', 403); - } - - /** - * Handles a web API delete request. - * - * @param string $plugin - * The resource type plugin. - * @param mixed $id - * The resource ID. - */ - public function delete($plugin, $id) { - if (user_access("restful delete $plugin")) { - $plugin = $this->container - ->get('plugin.manager.rest') - ->createInstance($plugin); - try { - return $plugin->delete($id); + return $resource->{$method}($id); } catch (ResourceException $e) { return new Response($e->getMessage(), $e->getCode()); diff --git a/core/modules/rest/lib/Drupal/rest/ResourceException.php b/core/modules/rest/lib/Drupal/rest/ResourceException.php index 34ecaff..57ba71d 100644 --- a/core/modules/rest/lib/Drupal/rest/ResourceException.php +++ b/core/modules/rest/lib/Drupal/rest/ResourceException.php @@ -12,7 +12,7 @@ * * The protected instance property $code is used as HTTP status code. */ -class ResourceException extends Exception { +class ResourceException extends \Exception { /** * Additional HTTP headers that should be returned with an error response. diff --git a/core/modules/rest/lib/Drupal/rest/ResourceInterface.php b/core/modules/rest/lib/Drupal/rest/ResourceInterface.php deleted file mode 100644 index d6c61ad..0000000 --- a/core/modules/rest/lib/Drupal/rest/ResourceInterface.php +++ /dev/null @@ -1,83 +0,0 @@ -assertResponse('204', 'HTTP response code is correct.'); $this->assertEqual($response, '', 'Response body is empty.'); + // Try to delete a node that does not exist. + $response = $this->httpRequest('entity/node/9999', 'DELETE'); + $this->assertResponse(404); + $this->assertEqual($response, 'Entity with ID 9999 not found', 'Response message is correct.'); + // Try to delete a resource which is not web API enabled. $this->httpRequest('entity/user/' . $account->id(), 'DELETE'); $user = entity_load('user', $account->id(), TRUE); diff --git a/core/modules/rest/lib/Drupal/rest/Tests/WatchdogTest.php b/core/modules/rest/lib/Drupal/rest/Tests/WatchdogTest.php index a610ff5..75d0ac0 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/WatchdogTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/WatchdogTest.php @@ -61,7 +61,7 @@ public function testWatchdog() { // Create a user account that has the required permissions to read // the watchdog resource via the web API. - $account = $this->drupalCreateUser(array('restful read watchdog')); + $account = $this->drupalCreateUser(array('restful get watchdog')); $this->drupalLogin($account); $response = $this->httpRequest("watchdog/$id", 'GET'); @@ -70,5 +70,10 @@ public function testWatchdog() { $this->assertEqual($log['wid'], $id, 'Log ID is correct.'); $this->assertEqual($log['type'], 'rest_test', 'Type of log message is correct.'); $this->assertEqual($log['message'], 'Test message', 'Log message text is correct.'); + + // Request an unknown log entry. + $response = $this->httpRequest("watchdog/9999", 'GET'); + $this->assertResponse(404); + $this->assertEqual($response, 'Not Found', 'Response message is correct.'); } } diff --git a/core/modules/rest/rest.module b/core/modules/rest/rest.module index 95aef40..7d59c83 100644 --- a/core/modules/rest/rest.module +++ b/core/modules/rest/rest.module @@ -32,15 +32,19 @@ function rest_menu() { function rest_route_info() { $collection = new RouteCollection(); - $manager = drupal_container()->get('plugin.manager.rest'); - $resources = config('rest')->get('resources'); - if ($resources && $enabled = array_intersect_key($manager->getDefinitions(), $resources)) { - foreach ($enabled as $key => $resource) { - $plugin = $manager->createInstance($key); + // This hook is called during module enabling where the manager has not been + // registered as service yet. + if (drupal_container()->has('plugin.manager.rest')) { + $manager = drupal_container()->get('plugin.manager.rest'); + $resources = config('rest')->get('resources'); + if ($resources && $enabled = array_intersect_key($manager->getDefinitions(), $resources)) { + foreach ($enabled as $key => $resource) { + $plugin = $manager->createInstance($key); - // @todo Switch to ->addCollection() once http://drupal.org/node/1819018 is resolved. - foreach ($plugin->routes() as $name => $route) { - $collection->add("rest.$name", $route); + // @todo Switch to ->addCollection() once http://drupal.org/node/1819018 is resolved. + foreach ($plugin->routes() as $name => $route) { + $collection->add("rest.$name", $route); + } } } } @@ -53,12 +57,14 @@ function rest_route_info() { */ function rest_permission() { $permissions = array(); - $manager = drupal_container()->get('plugin.manager.rest'); - $resources = config('rest')->get('resources'); - if ($resources && $enabled = array_intersect_key($manager->getDefinitions(), $resources)) { - foreach ($enabled as $key => $resource) { - $plugin = $manager->createInstance($key); - $permissions = array_merge($permissions, $plugin->permissions()); + if (drupal_container()->has('plugin.manager.rest')) { + $manager = drupal_container()->get('plugin.manager.rest'); + $resources = config('rest')->get('resources'); + if ($resources && $enabled = array_intersect_key($manager->getDefinitions(), $resources)) { + foreach ($enabled as $key => $resource) { + $plugin = $manager->createInstance($key); + $permissions = array_merge($permissions, $plugin->permissions()); + } } } return $permissions;