-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ACMS-000: Add the Multisite global drush command.
- Loading branch information
1 parent
18f9c5b
commit 5502227
Showing
3 changed files
with
234 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Acquia\Drupal\RecommendedSettings\Drush\Commands; | ||
|
||
use Acquia\Drupal\RecommendedSettings\Helpers\EnvironmentDetector; | ||
use Consolidation\AnnotatedCommand\CommandData; | ||
use Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface; | ||
use Consolidation\AnnotatedCommand\Events\CustomEventAwareTrait; | ||
use Consolidation\AnnotatedCommand\Hooks\HookManager; | ||
use Drush\Attributes as CLI; | ||
use Drush\Commands\DrushCommands; | ||
|
||
/** | ||
* This | ||
*/ | ||
class HooksDrushCommands extends DrushCommands { | ||
|
||
/** | ||
* Generate settings.php for multisite if current env. is not Site factory. | ||
*/ | ||
#[CLI\Hook(type: HookManager::ON_EVENT, target: MultisiteDrushCommands::VALIDATE_GENERATE_SETTINGS)] | ||
public function isAcquiaEnvironment(): bool { | ||
return !EnvironmentDetector::isAcsfEnv(); | ||
} | ||
|
||
/** | ||
* Generate settings.php for multisite if current env. is local or CloudIDE. | ||
*/ | ||
#[CLI\Hook(type: HookManager::ON_EVENT, target: MultisiteDrushCommands::VALIDATE_GENERATE_SETTINGS)] | ||
public function isLocalEnvironment(): bool { | ||
return (EnvironmentDetector::isLocalEnv() || EnvironmentDetector::isAhIdeEnv()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Acquia\Drupal\RecommendedSettings\Drush\Commands; | ||
|
||
use Acquia\Drupal\RecommendedSettings\Drush\Traits\SiteUriTrait; | ||
use Acquia\Drupal\RecommendedSettings\Helpers\EnvironmentDetector; | ||
use Acquia\Drupal\RecommendedSettings\Settings; | ||
use Consolidation\AnnotatedCommand\CommandData; | ||
use Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface; | ||
use Consolidation\AnnotatedCommand\Events\CustomEventAwareTrait; | ||
use Consolidation\AnnotatedCommand\Hooks\HookManager; | ||
use Drupal\Core\Database\Database; | ||
use Drush\Attributes as CLI; | ||
use Drush\Boot\BootstrapManager; | ||
use Drush\Boot\DrupalBootLevels; | ||
use Drush\Commands\DrushCommands; | ||
use Drush\Drush; | ||
use Psr\Container\ContainerInterface as DrushContainer; | ||
use Symfony\Component\Filesystem\Path; | ||
|
||
/** | ||
* A Drush command to generate settings.php for Multisite. | ||
*/ | ||
class MultisiteDrushCommands extends DrushCommands implements CustomEventAwareInterface { | ||
|
||
use CustomEventAwareTrait; | ||
use SiteUriTrait; | ||
|
||
const VALIDATE_GENERATE_SETTINGS = 'validate-generate-settings'; | ||
const POST_GENERATE_SETTINGS = 'post-generate-settings'; | ||
|
||
/** | ||
* Construct an object of Multisite commands. | ||
*/ | ||
public function __construct(private BootstrapManager $bootstrapManager) { | ||
parent::__construct(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public static function createEarly(DrushContainer $drush_container): self { | ||
return new static( | ||
$drush_container->get('bootstrap.manager') | ||
); | ||
} | ||
|
||
/** | ||
* Execute code before pre-validate site:install. | ||
*/ | ||
#[CLI\Hook(type: HookManager::PRE_ARGUMENT_VALIDATOR, target: 'site-install')] | ||
public function preValidateSiteInstall(CommandData $commandData): void { | ||
if ($this->validateGenerateSettings()) { | ||
$uri = $commandData->input()->getOption('uri') ?? 'default'; | ||
$sitesSubdir = $this->getSitesSubdirFromUri(DRUPAL_ROOT, $uri); | ||
$commandData->input()->setOption('sites-subdir', $sitesSubdir); | ||
$options = $commandData->options(); | ||
$this->bootstrapManager->setUri('http://' . $sitesSubdir); | ||
|
||
// Try to get any already configured database information. | ||
$this->bootstrapManager->bootstrapMax(DrupalBootLevels::CONFIGURATION, $commandData->annotationData()); | ||
|
||
// By default, bootstrap manager boot site from default/setting.php | ||
// hence remove the database connection if site is other than default. | ||
if (($sitesSubdir && "sites/$sitesSubdir" !== $this->bootstrapManager->bootstrap()->confpath())) { | ||
Database::removeConnection('default'); | ||
$db = [ | ||
'database' => 'drupal', | ||
'username' => 'drupal', | ||
'password' => 'drupal', | ||
'host' => 'localhost', | ||
'port' => '3306', | ||
]; | ||
$dbSpec = [ | ||
"drupal" => ["db" => $db] | ||
]; | ||
if (!($options['db-url'])) { | ||
if (EnvironmentDetector::isLocalEnv()) { | ||
$db = $this->askDbCredentials($sitesSubdir, $db); | ||
$dbSpec["drupal"]["db"] = $db; | ||
} | ||
$commandData->input()->setOption("db-url", | ||
"mysql://" . $db['username'] . ":" . $db['password'] . "@" . $db['host'] . ":" . $db['port'] . "/" . $db['database'] | ||
); | ||
} | ||
$settings = new Settings(DRUPAL_ROOT, $sitesSubdir); | ||
try { | ||
$settings->generate($dbSpec); | ||
$this->postGenerateSettings(); | ||
} | ||
catch (SettingsException $e) { | ||
$this->io()->warning($e->getMessage()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Function to check if multisite should be setup or not. | ||
*/ | ||
protected function validateGenerateSettings(): bool { | ||
$handlers = $this->getCustomEventHandlers(self::VALIDATE_GENERATE_SETTINGS); | ||
$status = TRUE; | ||
foreach ($handlers as $handler) { | ||
$status = $handler(); | ||
if (!$status) { | ||
return FALSE; | ||
} | ||
} | ||
return $status; | ||
} | ||
|
||
/** | ||
* Function to run if post generation of settings.php. | ||
*/ | ||
protected function postGenerateSettings(string $eventName): void { | ||
$handlers = $this->getCustomEventHandlers(self::POST_GENERATE_SETTINGS); | ||
foreach ($handlers as $handler) { | ||
$handler(); | ||
} | ||
} | ||
|
||
/** | ||
* Get local database specs. | ||
* | ||
* @param string $site_name | ||
* The site name. | ||
* | ||
* @return array | ||
* The database specs. | ||
*/ | ||
private function askDbCredentials(string $site_name, array $defaultCredentials): array { | ||
$shouldAsk = $this->io()->confirm(dt("Would you like to configure the local database credentials?")); | ||
$credentials = $defaultCredentials; | ||
if ($shouldAsk) { | ||
$credentials['database'] = $this->io()->ask("Local database name", $site_name); | ||
$credentials['username'] = $this->io()->ask("Local database user", $credentials['username']); | ||
$credentials['password'] = $this->io()->ask("Local database password", $credentials['password']); | ||
$credentials['host'] = $this->io()->ask("Local database host", $credentials['host']); | ||
$credentials['port'] = $this->io()->ask("Local database port", $credentials['port']); | ||
} | ||
return $credentials; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Acquia\Drupal\RecommendedSettings\Drush\Traits; | ||
|
||
use Symfony\Component\Filesystem\Path; | ||
|
||
/** | ||
* Trait to deletermine Site Uri. | ||
*/ | ||
trait SiteUriTrait { | ||
|
||
/** | ||
* Determine an appropriate site subdir name to use for the provided uri. | ||
* | ||
* This code copied from SiteInstallCommands.php file. | ||
* | ||
* @return array|false|mixed|string|string[] | ||
* Returns the site uri. | ||
*/ | ||
private function getSitesSubdirFromUri($root, $uri): mixed { | ||
$dir = strtolower($uri); | ||
// Always accept simple uris (e.g. 'dev', 'stage', etc.) | ||
if (preg_match('#^[a-z0-9_-]*$#', $dir)) { | ||
return $dir; | ||
} | ||
// Strip off the protocol from the provided uri -- however, | ||
// now we will require that the sites subdir already exist. | ||
$dir = preg_replace('#[^/]*/*#', '', $dir); | ||
if ($dir && file_exists(Path::join($root, $dir))) { | ||
return $dir; | ||
} | ||
// Find the dir from sites.php file. | ||
$sites_file = $root . '/sites/sites.php'; | ||
if (file_exists($sites_file)) { | ||
$sites = []; | ||
include $sites_file; | ||
if (!empty($sites) && array_key_exists($uri, $sites)) { | ||
return $sites[$uri]; | ||
} | ||
} | ||
// Fall back to default directory if it exists. | ||
if (file_exists(Path::join($root, 'sites', 'default'))) { | ||
return 'default'; | ||
} | ||
|
||
return FALSE; | ||
} | ||
|
||
} |