Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save pmichelazzo/744aca841bc503e4e4d2f3d8baa26ccd to your computer and use it in GitHub Desktop.
Save pmichelazzo/744aca841bc503e4e4d2f3d8baa26ccd to your computer and use it in GitHub Desktop.
Example Dynamic node route in drupal 8.
name: Example
type: module
description: Provides a homepage route based on a publish schedule date range field.
package: Example
core: 8.x
dependencies:
- node
example.home:
path: '/home'
defaults:
_controller: '\Drupal\node\Controller\NodeViewController::view'
_title_callback: '\Drupal\node\Controller\NodeViewController::title'
requirements:
_entity_access: 'node.view'
options:
_route_enhancers: 'route_enhancer.example.homepage'
services:
route_enhancer.example.homepage:
class: Drupal\example\Routing\Enhancer\HomepageEnhancer
arguments: ['@entity.query', '@entity_type.manager']
tags:
- { name: route_enhancer }
<?php
/**
* @file `tests/src/Kernel/ExampleHomepageResolverTest.php`
*
* Provides kernel tests for the HomepageEnhancer.
*/
namespace Drupal\Tests\example\Kernel;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\Node;
use Drupal\simpletest\ContentTypeCreationTrait;
use Drupal\simpletest\UserCreationTrait;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests homepage resolution.
*
* @group example
* @coversDefaultClass \Drupal\example\Routing\Enhancer\HomepageEnhancer
*/
class ExampleHomepageResolverTest extends FieldKernelTestBase {
use UserCreationTrait;
use ContentTypeCreationTrait;
/**
* A field storage to use in this test class.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field used in this test class.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* {@inheritdoc}
*/
public static $modules = [
'node',
'datetime',
'datetime_range',
'example',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installSchema('node', 'node_access');
$this->installConfig('node');
// Create a node type.
$this->createContentType(array(
'type' => 'homepage',
'name' => 'Homepage',
'display_submitted' => FALSE,
));
// Add a datetime range field.
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => 'field_schedule',
'entity_type' => 'node',
'type' => 'daterange',
'settings' => ['datetime_type' => DateRangeItem::DATETIME_TYPE_DATE],
]);
$this->fieldStorage->save();
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => 'homepage',
'required' => TRUE,
]);
$this->field->save();
}
/**
* Tests the homepage resolves according to the date.
*/
public function testHomepageResolver() {
$this->fieldStorage->setSetting('datetime_type', DateRangeItem::DATETIME_TYPE_DATE);
$field_name = $this->fieldStorage->getName();
$start_date = new DrupalDateTime('-3 Days');
$end_date = new DrupalDateTime('-2 Days');
// Create an expired homepage node.
$homepage_expired = Node::create([
'title' => $this->randomMachineName(),
'type' => 'homepage',
$field_name => [
'value' => $start_date->format(DATETIME_DATE_STORAGE_FORMAT),
'end_value' => $end_date->format(DATETIME_DATE_STORAGE_FORMAT),
],
]);
$homepage_expired->save();
$start_date = new DrupalDateTime('-15 Days');
$end_date = new DrupalDateTime('+15 Days');
// Create a valid homepage node.
$homepage_current = Node::create([
'title' => $this->randomMachineName(),
'type' => 'homepage',
$field_name => [
'value' => $start_date->format(DATETIME_DATE_STORAGE_FORMAT),
'end_value' => $end_date->format(DATETIME_DATE_STORAGE_FORMAT),
],
]);
$homepage_current->save();
$authenticated_user = $this->createUser(['access content']);
\Drupal::service('account_switcher')->switchTo($authenticated_user);
$request = Request::create('/home');
$kernel = \Drupal::getContainer()->get('http_kernel');
$response = $kernel->handle($request);
// Make sure access content is enough to see the homepage node.
self::assertSame(200, $response->getStatusCode());
// Make sure the current homepage is the one that resolves.
self::assertSame($homepage_current->id(), $request->attributes->get('node')->id(), 'The homepage is resolved');
// Used for text assertions.
$this->setRawContent($response->getContent());
// Make sure the correct title is rendered.
$this->assertText($homepage_current->getTitle());
}
}
<?php
/**
* @file `src/Routing/Enhancer/HomepageEnhancer.php`
*
* The HomepageEnhancer class is responsible for supplying the current homepage
* node that should be displayed dependent on the schedule.
*
* This module assumes the `homepage` content type with the `field_schedule`
* daterange field has been created.
*/
namespace Drupal\example\Routing\Enhancer;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Routing\Enhancer\RouteEnhancerInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
class HomepageEnhancer implements RouteEnhancerInterface {
/**
* The query factory.
*
* @var \Drupal\Core\Entity\Query\QueryFactoryInterface
*/
protected $entity_query;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entity_type_manager;
/**
* Constructs an HomepageEnhancer instance.
*
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query
* The entity resolver manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(QueryFactory $entity_query, EntityTypeManagerInterface $entity_type_manager) {
$this->entity_query = $entity_query;
$this->entity_type_manager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public function enhance(array $defaults, Request $request) {
if (empty($defaults['node'])) {
// Use a datetime object to get the current time.
$now = new DrupalDateTime('now');
$sql_time = $now->format(DATETIME_DATE_STORAGE_FORMAT);
// Get the latest published homepage.
$homepage_result = $this->entity_query->get('node')
->condition('type', 'homepage')
->condition('field_schedule', $sql_time, '<=')
->condition('field_schedule.end_value', $sql_time, '>=')
->condition('status', 1)
->sort('field_schedule', 'DESC')
->range(0,1)
->execute();
$nid = reset($homepage_result);
if (!empty($nid)) {
// Get the Symfony route object.
$route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
// If we don't set the default nid route match won't work meaning that access checks will fail and node context won't be available.
$route->setDefault('node', $nid);
// This is the enhancement part, setting the node object.
$defaults['node'] = $this->entity_type_manager->getStorage('node')->load($nid);
}
}
return $defaults;
}
/**
* {@inheritdoc}
*/
public function applies(Route $route) {
// Only applies to the homepage route.
return TRUE;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment