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..4863b81 100644
--- a/core/modules/rest/rest.module
+++ b/core/modules/rest/rest.module
@@ -43,3 +43,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'] = check_plain($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..bbfbee2
--- /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(),
+ );
+ return $render;
+ }
+
+ 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..5587ee6 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,102 @@ protected function alterRoutes(RouteCollection $collection) {
}
}
+ /**
+ * @param RouteBuildEvent $event
+ */
+ public function resourceRoutes(RouteBuildEvent $event) {
+ $collection = $event->getRouteCollection();
+
+ $resources = $this->manager->getDefinitions();
+ foreach ($resources as $id => $resource) {
+ $plugin = $this->manager->getInstance(array('id' => $id));
+
+ foreach ($plugin->routes() as $name => $route) {
+ $route->setRequirement('_access_rest_csrf', 'FALSE');
+ $collection->add("rest.$name", $route);
+ $collection->add("rest.resource.$name", $route);
+ }
+ }
+ }
+
+ public function relationRoutes(RouteBuildEvent $event) {
+ // TODO: Missing bundle for entity type contact_message
+ return;
+ $collection = $event->getRouteCollection();
+
+ $link_field_types = array(
+ 'entity_reference',
+ 'taxonomy_term_reference',
+ );
+
+ foreach (entity_get_bundles() as $entity_type => $bundles) {
+ foreach ($bundles as $bundle_name => $bundle) {
+ if (in_array($entity_type, array('comment', 'block'))) {
+ 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) {
+ if ($field_definition->getType() == 'entity_reference_field') {
+ $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();
+
+ // TODO fix method resourceRoutes
+ $events[RoutingEvents::DYNAMIC][] = array('resourceRoutes');
+ // TODO fix relationRoutes
+ // drush cache-rebuild generated
+ // Missing bundle for entity type contact_message
+ //$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 %}
+