diff --git a/core/modules/rest/1925618-07-rest-docs-REMAINS.patch b/core/modules/rest/1925618-07-rest-docs-REMAINS.patch new file mode 100644 index 0000000..59bcd53 --- /dev/null +++ b/core/modules/rest/1925618-07-rest-docs-REMAINS.patch @@ -0,0 +1,38 @@ +diff --git a/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php b/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php +index d4711e0..35ce1d3 100644 +--- a/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php ++++ b/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php +@@ -7,11 +7,13 @@ + namespace Drupal\rest\EventSubscriber; + + use Drupal\Core\Config\ConfigFactory; ++use Drupal\Core\Entity\EntityNG; + use Drupal\Core\Routing\RouteBuildEvent; + use Drupal\Core\Routing\RoutingEvents; + use Drupal\rest\Plugin\Type\ResourcePluginManager; + + use Symfony\Component\EventDispatcher\EventSubscriberInterface; ++use Symfony\Component\Routing\Route; + + /** + * Subscriber for REST-style routes. +@@ -51,7 +53,7 @@ public function __construct(ResourcePluginManager $manager, ConfigFactory $confi + * @param \Drupal\Core\Routing\RouteBuildEvent $event + * The route building event. + */ +- public function dynamicRoutes(RouteBuildEvent $event) { ++ public function resourceRoutes(RouteBuildEvent $event) { + + $collection = $event->getRouteCollection(); + +@@ -62,17 +64,71 @@ public function dynamicRoutes(RouteBuildEvent $event) { + + foreach ($plugin->routes() as $name => $route) { + $route->setRequirement('_access_rest_csrf', 'TRUE'); +- $collection->add("rest.$name", $route); ++ $collection->add("rest.resource.$name", $route); + } + } + } + } + } diff --git a/core/modules/rest/rest.module b/core/modules/rest/rest.module index c0c6be3..d453824 100644 --- a/core/modules/rest/rest.module +++ b/core/modules/rest/rest.module @@ -5,6 +5,7 @@ * RESTful web services module. */ +use Drupal\Component\Utility\String; use Drupal\Core\Routing\RouteMatchInterface; /** @@ -43,3 +44,24 @@ function rest_help($route_name, RouteMatchInterface $route_match) { return $output; } } + + +/** + * Implements hook_theme(). + */ +function rest_theme() { + return array( + 'rest_documentation' => array( + 'variables' => array('field_description' => NULL, 'methods' => array()), + 'template' => 'rest-documentation', + ), + 'rest_documentation_section' => array( + 'variables' => array('method' => NULL, 'headers' => NULL, 'body' => NULL), + 'template' => 'rest-documentation-section', + ), + ); +} + +function template_preprocess_rest_documentation($variables) { + $variables['field_description'] = String::checkPlain($variables['field_description']); +} diff --git a/core/modules/rest/src/Controller.php b/core/modules/rest/src/Controller.php new file mode 100644 index 0000000..6447498 --- /dev/null +++ b/core/modules/rest/src/Controller.php @@ -0,0 +1,77 @@ + 'rest_documentation_section', + '#method' => 'GET', + '#headers' => array( + '#theme' => 'item_list', + '#title' => t('HTTP Headers'), + '#items' => array( + 'Link: <http://drupal.org/rest>; rel="profile"' + ), + ), + // @todo Add required and optional fields here. + '#body' => array(), + ); + // TODO : make this a proper content response somehow. + $response = new Response(); + $response->setContent(drupal_render($render)); + return $response; + } + + public function type($entity_type, $bundle) { + // TODO: fix for CR https://www.drupal.org/node/2067859 + //drupal_set_title($entity_type . ': ' . $bundle); + + $required = array(); + $optional = array(); + + $entity = entity_create($entity_type, array('type' => $bundle)); + foreach ($entity->getProperties() as $field) { + $definition = $field->getItemDefinition(); + if (isset($definition['required'])) { + $required[] = $field->getName(); + } + else { + $optional[] = $field->getName(); + } + } + + $render = array( + array( + '#theme' => 'item_list', + '#title' => t('Required fields'), + '#items' => $required, + ), + array( + '#theme' => 'item_list', + '#title' => t('Optional fields'), + '#items' => $optional, + ), + ); + + // TODO : make this a proper content response somehow. + $response = new Response(); + $response->setContent(drupal_render($render)); + return $response; + } +} diff --git a/core/modules/rest/src/Routing/ResourceRoutes.php b/core/modules/rest/src/Routing/ResourceRoutes.php index 5605048..0da1817 100644 --- a/core/modules/rest/src/Routing/ResourceRoutes.php +++ b/core/modules/rest/src/Routing/ResourceRoutes.php @@ -9,16 +9,21 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; +use Drupal\Core\Entity\ContentEntityBase; +use Drupal\Core\Routing\RouteBuildEvent; use Drupal\Core\Routing\RouteSubscriberBase; +use Drupal\Core\Routing\RoutingEvents; use Drupal\rest\Plugin\Type\ResourcePluginManager; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; + /** * Subscriber for REST-style routes. */ -class ResourceRoutes extends RouteSubscriberBase{ +class ResourceRoutes extends RouteSubscriberBase { /** * The plugin manager for REST plugins. @@ -66,7 +71,7 @@ protected function alterRoutes(RouteCollection $collection) { $method = $route->getRequirement('_method'); // Only expose routes where the method is enabled in the configuration. if ($method && isset($enabled_methods[$method])) { - $route->setRequirement('_access_rest_csrf', 'TRUE'); + $route->setRequirement('_access_rest_csrf', 'TRUE'); // Check that authentication providers are defined. if (empty($enabled_methods[$method]['supported_auth']) || !is_array($enabled_methods[$method]['supported_auth'])) { @@ -97,4 +102,95 @@ protected function alterRoutes(RouteCollection $collection) { } } + public function relationRoutes(RouteBuildEvent $event) { + $collection = $event->getRouteCollection(); + + $link_field_types = array( + 'entity_reference', + 'taxonomy_term_reference', + ); + + foreach (entity_get_bundles() as $entity_type => $bundles) { + // TODO fix relationRoutes + // drush cache-rebuild generated + + $skip = array( + 'comment', // Missing bundle for entity type comment + //'block', + 'contact_message', // Missing bundle for entity type contact_message + 'breakpoint', // Attempt to create an unnamed breakpoint. + 'breakpoint_group', // Attempt to create an unnamed breakpoint group. + 'editor', // The "" plugin does not exist. + 'entity_form_display', // Missing required properties for an EntityDisplay entity.' + 'entity_view_display', // Missing required properties for an EntityDisplay entity.' + 'field_config', // Attempt to create an unnamed field.' + 'field_instance_config', // Attempt to create an instance of a field without a field_name.' + 'taxonomy_term', // Missing bundle for entity type taxonomy_term + ); + foreach ($bundles as $bundle_name => $bundle) { + if (in_array($entity_type, $skip)) { + continue; + } + /** + * @var $entity \Drupal\Core\Entity\EntityInterface + */ + $entity = entity_create($entity_type, array('type' => $bundle_name)); + if ($entity instanceof ContentEntityBase) { + /** + * @var $fields \Drupal\Core\Field\FieldDefinitionInterface[] + */ + $fields = $entity->getFieldDefinitions(); + /** + * @var $field_definition \Drupal\Core\Field\FieldDefinitionInterface + */ + foreach ($fields as $field_name => $field_definition) { + $field_type = $field_definition->getType(); + if (in_array($field_type, $link_field_types)) { + // echo "$entity_type:$bundle_name:$field_name is a : " . $field_type . PHP_EOL; + $route = new Route("/rest/relations/$entity_type/$bundle_name/$field_name", array( + '_controller' => 'Drupal\rest\Controller::relation', + 'field_name' => $field_name, + 'field_definition' => $field_definition, + ), array( + '_method' => 'GET', + '_access' => 'TRUE', + )); + $collection->add("rest.relation.$entity_type.$bundle_name.$field_name", $route); + } + } + } + } + } + } + + public function typeRoutes(RouteBuildEvent $event) { + $collection = $event->getRouteCollection(); + + // @todo Change this to only expose info for REST enabled entity types. + foreach (entity_get_bundles() as $entity_type => $bundles) { + foreach ($bundles as $bundle_name => $bundle) { + $route = new Route("/rest/types/$entity_type/$bundle_name", array( + '_controller' => 'Drupal\rest\Controller::type', + 'entity_type' => $entity_type, + 'bundle' => $bundle_name, + ), array( + '_method' => 'GET', + '_access' => 'TRUE', + )); + $collection->add("rest.type.$entity_type.$bundle_name", $route); + } + } + } + + /** + * Implements EventSubscriberInterface::getSubscribedEvents(). + */ + static function getSubscribedEvents() { + $events = parent::getSubscribedEvents(); + + $events[RoutingEvents::DYNAMIC][] = array('relationRoutes'); + $events[RoutingEvents::DYNAMIC][] = array('typeRoutes'); + return $events; + } + } diff --git a/core/modules/rest/templates/rest-documentation-section.html.twig b/core/modules/rest/templates/rest-documentation-section.html.twig new file mode 100644 index 0000000..2ae3afc --- /dev/null +++ b/core/modules/rest/templates/rest-documentation-section.html.twig @@ -0,0 +1,9 @@ +
+ +

{{ method }}

+ {% if headers %} +{# TODO : fix call to render + {{ render(headers) }} +#} + {% endif %} +
diff --git a/core/modules/rest/templates/rest-documentation.html.twig b/core/modules/rest/templates/rest-documentation.html.twig new file mode 100644 index 0000000..0715efa --- /dev/null +++ b/core/modules/rest/templates/rest-documentation.html.twig @@ -0,0 +1,6 @@ +
+ {{ field_description }} +{# TODO : fix call to render + {{ render(methods) }} +#} +
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php old mode 100644 new mode 100755