Skip to content
Snippets Groups Projects
Unverified Commit c3e3008b authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3490843 by nicxvan, smustgrave, oily, joachim, berdir, alexpott,...

Issue #3490843 by nicxvan, smustgrave, oily, joachim, berdir, alexpott, nikolay shapovalov, dww: Create class to replace hook_requirements('install')
parent fae1be90
No related branches found
No related tags found
No related merge requests found
Checking pipeline status
Showing
with 280 additions and 3 deletions
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\Extension\Dependency; use Drupal\Core\Extension\Dependency;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\InstallRequirementsInterface;
use Drupal\Core\Installer\InstallerKernel; use Drupal\Core\Installer\InstallerKernel;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
...@@ -616,6 +618,8 @@ function drupal_check_profile($profile) { ...@@ -616,6 +618,8 @@ function drupal_check_profile($profile) {
if (function_exists($function)) { if (function_exists($function)) {
$requirements = array_merge($requirements, $function('install')); $requirements = array_merge($requirements, $function('install'));
} }
$requirements = array_merge($requirements, install_check_class_requirements($module_list[$module]));
} }
} }
...@@ -625,6 +629,9 @@ function drupal_check_profile($profile) { ...@@ -625,6 +629,9 @@ function drupal_check_profile($profile) {
$requirements = array_merge($requirements, $function('install')); $requirements = array_merge($requirements, $function('install'));
} }
$extension = \Drupal::service('extension.list.profile')->get($profile);
$requirements = array_merge($requirements, install_check_class_requirements($extension));
return $requirements; return $requirements;
} }
...@@ -660,13 +667,16 @@ function drupal_requirements_severity(&$requirements) { ...@@ -660,13 +667,16 @@ function drupal_requirements_severity(&$requirements) {
function drupal_check_module($module) { function drupal_check_module($module) {
/** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */ /** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
$module_list = \Drupal::service('extension.list.module'); $module_list = \Drupal::service('extension.list.module');
$file = DRUPAL_ROOT . '/' . $module_list->getPath($module) . "/$module.install"; $extension = $module_list->get($module);
$file = \Drupal::root() . '/' . $extension->getPath() . "/$module.install";
if (is_file($file)) { if (is_file($file)) {
require_once $file; require_once $file;
} }
// Check requirements // Check requirements
$requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']); $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? [];
if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) { $requirements = array_merge($requirements, install_check_class_requirements($extension));
if (!empty($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
// Print any error messages // Print any error messages
foreach ($requirements as $requirement) { foreach ($requirements as $requirement) {
if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) { if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
...@@ -790,3 +800,41 @@ function install_profile_info($profile, $langcode = 'en') { ...@@ -790,3 +800,41 @@ function install_profile_info($profile, $langcode = 'en') {
} }
return $cache[$profile][$langcode]; return $cache[$profile][$langcode];
} }
/**
* Checks a module or profile requirements.
*
* See \Drupal\Core\Extension\InstallRequirementsInterface for more information.
*
* @param \Drupal\Core\Extension $extension
* The extension to check install requirements for.
*
* @return array
* The requirements.
*
* @internal
*/
function install_check_class_requirements(Extension $extension): array {
$extension_path = $extension->getPath();
$extension_name = $extension->getName();
$dir = \Drupal::root() . "/$extension_path/src/Install/Requirements";
$requirements = [];
if (is_dir($dir)) {
$fileSystemIterator = new FilesystemIterator($dir);
foreach ($fileSystemIterator as $fileInfo) {
if ($fileInfo->isFile() && $fileInfo->getExtension() === 'php') {
$filename = $fileInfo->getFilename();
$requirements_path = $dir . '/' . $filename;
require_once $requirements_path;
$namespace = "Drupal\\$extension_name\\Install\\Requirements";
$class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
if (class_exists($class_name) && class_implements($class_name, InstallRequirementsInterface::class)) {
$requirements = $class_name::getRequirements();
}
}
}
}
return $requirements;
}
<?php
namespace Drupal\Core\Extension;
/**
* Provides method for checking requirements during install time.
*/
interface InstallRequirementsInterface {
/**
* Check installation requirements.
*
* Classes implementing this must be in the Install/Requirements namespace.
* For example src/Install/Requirements/ModuleNameRequirements.php.
*
* During the 'install' phase, modules can for example assert that
* library or server versions are available or sufficient.
* Note that the installation of a module can happen during installation of
* Drupal itself (by install.php) with an installation profile or later by hand.
* As a consequence, install-time requirements must be checked without access
* to the full Drupal API, because it is not available during install.php.
* If a requirement has a severity of REQUIREMENT_ERROR, install.php will abort
* or at least the module will not install.
* Other severity levels have no effect on the installation.
* Module dependencies do not belong to these installation requirements,
* but should be defined in the module's .info.yml file.
*
* During installation, if you need to load a class from your module,
* you'll need to include the class file directly.
*
* @return array
* An associative array where the keys are arbitrary but must be unique (it
* is suggested to use the module short name as a prefix) and the values are
* themselves associative arrays with the following elements:
* - title: The name of the requirement.
* - value: This should only be used for version numbers, do not set it if
* not applicable.
* - description: The description of the requirement/status.
* - severity: (optional) The requirement's result/severity level, one of:
* - REQUIREMENT_INFO: For info only.
* - REQUIREMENT_OK: The requirement is satisfied.
* - REQUIREMENT_WARNING: The requirement failed with a warning.
* - REQUIREMENT_ERROR: The requirement failed with an error.
* Defaults to REQUIREMENT_OK when installing.
*/
public static function getRequirements(): array;
}
name: 'Test Install Requirements Class'
type: module
description: 'Support module for testing install requirements.'
package: Testing
version: VERSION
<?php
declare(strict_types=1);
namespace Drupal\module_install_requirements\Install\Requirements;
use Drupal\Core\Extension\InstallRequirementsInterface;
/**
* Provides method for checking requirements during install time.
*/
class ModuleInstallRequirements implements InstallRequirementsInterface {
/**
* {@inheritdoc}
*/
public static function getRequirements(): array {
$GLOBALS['module_install_requirements'] = 'module_install_requirements';
return [];
}
}
name: 'Test Install Requirements Class'
type: module
description: 'Support module for testing install unmet requirements.'
package: Testing
version: VERSION
<?php
declare(strict_types=1);
namespace Drupal\module_install_unmet_requirements\Install\Requirements;
use Drupal\Core\Extension\InstallRequirementsInterface;
/**
* Provides method for checking requirements during install time.
*/
class ModuleInstallUnmetRequirementsRequirements implements InstallRequirementsInterface {
/**
* {@inheritdoc}
*/
public static function getRequirements(): array {
$requirements['testing_requirements'] = [
'title' => t('Testing requirements'),
'severity' => REQUIREMENT_ERROR,
'description' => t('Testing requirements failed requirements.'),
];
return $requirements;
}
}
name: 'Test Install Requirements'
type: profile
hidden: true
description: 'Support profile for testing install requirements.'
version: VERSION
<?php
declare(strict_types=1);
namespace Drupal\profile_install_requirements\Install\Requirements;
use Drupal\Core\Extension\InstallRequirementsInterface;
/**
* Provides method for checking requirements during install time.
*/
class ProfileInstallRequirementsRequirements implements InstallRequirementsInterface {
/**
* {@inheritdoc}
*/
public static function getRequirements(): array {
$requirements['testing_requirements'] = [
'title' => t('Testing requirements'),
'severity' => REQUIREMENT_ERROR,
'description' => t('Testing requirements failed requirements.'),
];
return $requirements;
}
}
<?php
declare(strict_types=1);
namespace Drupal\FunctionalTests\Installer;
/**
* Tests installing a profile that implements InstallRequirementsInterface.
*
* @group Installer
*/
class ProfileRequirementsTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected $profile = 'profile_install_requirements';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUpSettings(): void {
// This form will never be reached.
}
/**
* {@inheritdoc}
*/
protected function setUpRequirementsProblem(): void {
// The parent method asserts that there are no requirements errors, but
// this test expects a requirements error in the test method below.
// Therefore, we override this method to suppress the parent's assertions.
}
/**
* {@inheritdoc}
*/
protected function setUpSite(): void {
// This form will never be reached.
}
/**
* Test Requirements are picked up.
*/
public function testRequirementsFailure(): void {
$this->assertSession()->pageTextContains('Testing requirements failed requirements.');
}
}
<?php
declare(strict_types=1);
namespace Drupal\KernelTests\Core\Installer;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests for install requirements.
*
* @group Installer
*/
class InstallRequirementsTest extends KernelTestBase {
/**
* Confirm installer checks requirements in designated classes.
*/
public function testRequirements(): void {
require_once 'core/includes/install.inc';
$this->assertFalse(isset($GLOBALS['module_install_requirements']));
drupal_check_module('module_install_requirements');
$this->assertTrue(isset($GLOBALS['module_install_requirements']));
}
/**
* Tests that the installer returns false if module requirements are not met.
*/
public function testRequirementsFailure(): void {
require_once 'core/includes/install.inc';
$this->assertFalse(drupal_check_module('module_install_unmet_requirements'));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment