Commit 44d99d9b authored by willzyx's avatar willzyx

Issue #2786541 by Manuel Garcia, romainj: Add page listing the available layouts on the site

parent a83e6a76
......@@ -26,6 +26,7 @@ use Drupal\Core\Url;
use Drupal\Core\Utility\Error;
use Drupal\devel\EntityTypeInfo;
use Drupal\devel\ToolbarHandler;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Implements hook_help().
......@@ -74,6 +75,11 @@ function devel_help($route_name, RouteMatchInterface $route_match) {
case 'devel.state_system_page':
return '<p>' . t('This is a list of state variables and their values. For more information read online documentation of <a href=":documentation">State API in Drupal 8</a>.', array(':documentation' => "https://www.drupal.org/developing/api/8/state")) . '</p>';
case 'devel.layout_info':
$output = '';
$output .= '<p>' . t('Displays layouts available to the site. For a complete overview of the layout system, see the <a href=":url">Layout API documentation</a>.', [':url' => 'https://www.drupal.org/docs/8/api/layout-api']) . '</p>';
return $output;
}
}
......@@ -104,6 +110,21 @@ function devel_toolbar() {
->toolbar();
}
/**
* Implements hook_menu_links_discovered_alter().
*/
function devel_menu_links_discovered_alter(&$links) {
// Conditionally add the Layouts info menu link.
if (\Drupal::moduleHandler()->moduleExists('layout_discovery')) {
$links['devel.layout_info'] = [
'title' => new TranslatableMarkup('Layouts Info'),
'route_name' => 'devel.layout_info',
'description' => new TranslatableMarkup('Overview of layouts available to the site.'),
'menu_name' => 'devel',
];
}
}
/**
* Implements hook_local_tasks_alter().
*/
......
......@@ -242,3 +242,15 @@ devel.event_info:
_admin_route: TRUE
requirements:
_permission: 'access devel information'
# Layouts info
devel.layout_info:
path: '/devel/layouts'
defaults:
_controller: '\Drupal\devel\Controller\LayoutInfoController::layoutInfoPage'
_title: 'Layouts'
options:
_admin_route: TRUE
requirements:
_permission: 'access devel information'
_module_dependencies: 'layout_discovery'
<?php
namespace Drupal\devel\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Layout\LayoutPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Returns response for Layout Info route.
*/
class LayoutInfoController extends ControllerBase {
/**
* The Layout Plugin Manager.
*
* @var Drupal\Core\Layout\LayoutPluginManagerInterface
*/
protected $layoutPluginManager;
/**
* LayoutInfoController constructor.
*
* @param \Drupal\Core\Layout\LayoutPluginManagerInterface $pluginManagerLayout
* The layout manager.
*/
public function __construct(LayoutPluginManagerInterface $pluginManagerLayout) {
$this->layoutPluginManager = $pluginManagerLayout;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.core.layout')
);
}
/**
* Builds the Layout Info page.
*
* @return array
* Array of page elements to render.
*/
public function layoutInfoPage() {
$definedLayouts = [];
$layouts = $this->layoutPluginManager->getDefinitions();
foreach ($layouts as $layout) {
// @todo Revisit once https://www.drupal.org/node/2660124 gets in, getting
// the image should be as simple as $layout->getIcon().
$image = NULL;
if ($layout->getIconPath() != NULL) {
$image = [
'data' => [
'#theme' => 'image',
'#uri' => $layout->getIconPath(),
'#alt' => $layout->getLabel(),
'#height' => '65',
]
];
}
$definedLayouts[] = [
$image,
$layout->getLabel(),
$layout->getDescription(),
$layout->getCategory(),
implode(', ', $layout->getRegionLabels()),
$layout->getProvider(),
];
}
return [
'#theme' => 'table',
'#header' => [
$this->t('Icon'),
$this->t('Label'),
$this->t('Description'),
$this->t('Category'),
$this->t('Regions'),
$this->t('Provider'),
],
'#rows' => $definedLayouts,
'#empty' => $this->t('No layouts available.'),
'#attributes' => [
'class' => ['devel-layout-list'],
],
];
}
}
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\Core\Layout\LayoutPluginManagerInterface;
/**
* Tests layout info pages and links.
*
* @group devel
*/
class DevelLayoutInfoTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'block', 'layout_discovery'];
/**
* The user for the test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests layout info menu link.
*/
public function testLayoutsInfoMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the layout info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Layouts Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/layouts');
$this->assertSession()->pageTextContains('Layout');
}
/**
* Tests layout info page.
*/
public function testEventList() {
$this->drupalGet('/devel/layouts');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Layouts');
$page = $this->getSession()->getPage();
// Ensures that the layout table is found.
$table = $page->find('css', 'table.devel-layout-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
/** @var $headers \Behat\Mink\Element\NodeElement[] */
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(6, count($headers));
$expected_headers = ['Icon', 'Label', 'Description', 'Category', 'Regions', 'Provider'];
$actual_headers = array_map(function ($element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Ensures that all the layouts are listed in the table.
$layout_manager = \Drupal::service('plugin.manager.core.layout');
$layouts = $layout_manager->getDefinitions();
$table_rows = $table->findAll('css', 'tbody tr');
$this->assertEquals(count($layouts), count($table_rows));
$index = 0;
foreach ($layouts as $layout) {
$cells = $table_rows[$index]->findAll('css', 'td');
$this->assertEquals(6, count($cells));
$cell_layout_icon = $cells[0];
if (empty($layout->getIconPath())) {
// @todo test that the icon path image is set correctly
}
else {
$this->assertNull($cell_layout_icon->getText());
}
$cell_layout_label = $cells[1];
$this->assertEqual($cell_layout_label->getText(), $layout->getLabel());
$cell_layout_description = $cells[2];
$this->assertEqual($cell_layout_description->getText(), $layout->getDescription());
$cell_layout_category = $cells[3];
$this->assertEqual($cell_layout_category->getText(), $layout->getCategory());
$cell_layout_regions = $cells[4];
$this->assertEqual($cell_layout_regions->getText(), implode(', ', $layout->getRegionLabels()));
$cell_layout_provider = $cells[5];
$this->assertEqual($cell_layout_provider->getText(), $layout->getProvider());
$index++;
}
// Ensures that the page is accessible only to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/layouts');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests the dependency with layout_discovery module.
*/
public function testLayoutDiscoveryDependency() {
$this->container->get('module_installer')->uninstall(['layout_discovery']);
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the layout info link is not present on the devel menu.
$this->drupalGet('');
$this->assertNoLink('Layouts Info');
// Ensures that the layouts info page is not available.
$this->drupalGet('/devel/layouts');
$this->assertSession()->statusCodeEquals(404);
// Check a few other devel pages to verify devel module stil works.
$this->drupalGet('/devel/events');
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet('devel/routes');
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet('/devel/container/service');
$this->assertSession()->statusCodeEquals(200);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment