Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Installing default blocks #212

Open
wants to merge 16 commits into
base: 2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions localgov_core.module
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,16 @@ function localgov_core_template_preprocess_default_variables_alter(&$variables)
$variables['localgov_base_remove_js'] = TRUE;
}
}

/**
* Implements hook_modules_installed().
*/
function localgov_core_modules_installed($modules) {

/** @var \Drupal\localgov_core\Service\DefaultBlockInstaller $defaultBlockInstaller */
$defaultBlockInstaller = \Drupal::service('localgov_core.default_block_installer');

foreach ($modules as $module) {
$defaultBlockInstaller->install($module);
}
}
4 changes: 4 additions & 0 deletions localgov_core.services.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
localgov_core.default_block_installer:
class: Drupal\localgov_core\Service\DefaultBlockInstaller
arguments: ['@entity_type.manager', '@file_system', '@module_handler', '@theme_handler', '@theme.manager']
178 changes: 178 additions & 0 deletions src/Service/DefaultBlockInstaller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php

namespace Drupal\localgov_core\Service;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Symfony\Component\Yaml\Yaml;

/**
* Service to install default blocks.
*/
class DefaultBlockInstaller {

/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;

/**
* File system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;

/**
* Theme handler.
*
* @var \Drupal\Core\Extension\ThemeHandlerInterface
*/
protected $themeHandler;

/**
* Theme manager.
*
* @var \Drupal\Core\Theme\ThemeManagerInterface
*/
protected $themeManager;

/**
* Theme handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;

/**
* Array of regions in each theme.
*
* @var array
*/
protected $themeRegions = [];

/**
* Constructor.
*/
public function __construct(
EntityTypeManagerInterface $entityTypeManager,
FileSystemInterface $fileSystem,
ModuleHandlerInterface $moduleHandler,
ThemeHandlerInterface $themeHandler,
ThemeManagerInterface $themeManager,
) {
$this->entityTypeManager = $entityTypeManager;
$this->fileSystem = $fileSystem;
$this->moduleHandler = $moduleHandler;
$this->themeHandler = $themeHandler;
$this->themeManager = $themeManager;
}

/**
* Read the yaml files provided by modules.
*/
protected function blockDefinitions(string $module): array {

$modulePath = $this->moduleHandler->getModule($module)->getPath();
$moduleBlockDefinitionsPath = $modulePath . '/config/localgov';
$blocks = [];

if (is_dir($moduleBlockDefinitionsPath)) {
$files = $this->fileSystem->scanDirectory($moduleBlockDefinitionsPath, '/block\..+\.yml$/');
foreach ($files as $file) {
$blocks[] = Yaml::parseFile($moduleBlockDefinitionsPath . '/' . $file->filename);
}
}

return $blocks;
}

/**
* The themes we'll be installing blocks into.
*/
protected function targetThemes(): array {

// @todo These should be a setting.
// @todo Add a setting at the same time to prevent default blocks being installed entirely.
$themes = ['localgov_base', 'localgov_scarfolk'];

// Don't try to use themes that don't exist.
foreach ($themes as $i => $theme) {
if (!$this->themeHandler->themeExists($theme)) {
unset($themes[$i]);
}
}

$activeTheme = $this->themeManager->getActiveTheme()->getName();

if (!in_array($activeTheme, $themes)) {
$themes[] = $activeTheme;
}

return $themes;
}

/**
* Installs the default blocks for the given module.
*/
public function install(string $module): void {

$blocks = $this->blockDefinitions($module);

// Loop over every theme and block definition, so we set up all the blocks
// in all the relevant themes.
foreach ($this->targetThemes() as $theme) {
foreach ($blocks as $block) {

if (!$this->themeHasRegion($theme, $block['region'])) {
continue;
}

$block['id'] = $this->sanitiseID($theme . '_' . $block['plugin']);
$block['theme'] = $theme;

$this->entityTypeManager
->getStorage('block')
->create($block)
->save();
}
}
}

/**
* Replace characters that aren't allowed in config IDs.
*/
protected function sanitiseID(string $id): string {
return preg_replace('/[^a-z0-9\._]/', '_', strtolower($id));
ekes marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Does the given theme have the given region?
*/
protected function themeHasRegion(string $theme, string $region): bool {
return in_array($region, $this->themeRegions($theme));
}

/**
* Gets the regions for the given theme.
*/
protected function themeRegions(string $theme): array {
if (!isset($this->themeRegions[$theme])) {
$themeInfo = $this->themeHandler->getTheme($theme);
if (empty($themeInfo)) {
$regions = [];
}
else {
$regions = array_keys($themeInfo->info['regions']);
}
$this->themeRegions[$theme] = $regions;
}
return $this->themeRegions[$theme];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugin: 'localgov_core_test_block'
region: bad_region
status: true
weight: 1
settings:
label: 'Block in a bad region.'
visibility: { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugin: 'localgov_core_test_block'
region: content_top
status: true
weight: 1
settings:
label: 'Block in a good region.'
visibility: { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: 'Default blocks test'
type: module
package: Testing
core_version_requirement: ^9 || ^10
description: Testing module for default blocks.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Drupal\localgov_core_default_blocks_test\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
* Provides a block for testing default block placement.
*
* @Block(
* id = "localgov_core_test_block",
* admin_label = @Translation("Default block test block")
* )
*/
class TestBlock extends BlockBase {

/**
* {@inheritdoc}
*/
public function build(): array {
return ['#markup' => 'Default block has been placed!'];
}

}
34 changes: 34 additions & 0 deletions tests/src/Functional/DefaultBlockTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Drupal\Tests\localgov_core\Functional;

use Drupal\Tests\BrowserTestBase;

/**
* Tests for the default blocks mechanism.
*/
class DefaultBlockTest extends BrowserTestBase {

/**
* {@inheritdoc}
*/
protected $defaultTheme = 'localgov_base';

/**
* {@inheritdoc}
*/
protected static $modules = [
'localgov_core',
'localgov_core_default_blocks_test',
];

/**
* Test block display.
*/
public function testBlockDisplay() {
$this->drupalGet('<front>');
$this->assertSession()->pageTextContains('Block in a good region.');
$this->assertSession()->pageTextNotContains('Block in a bad region.');
}

}
Loading