Newer
Older

Adam G-H
committed
<?php
namespace Drupal\package_manager\EventSubscriber;
use Drupal\Core\Database\Connection;
use Drupal\Core\File\FileSystemInterface;

Adam G-H
committed
use Drupal\Core\StreamWrapper\LocalStream;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Defines an event subscriber to exclude certain paths from staging areas.
*/
class ExcludedPathsSubscriber implements EventSubscriberInterface {
/**
* The Drupal root.
*
* @var string
*/
protected $appRoot;

Adam G-H
committed
/**
* The current site path, relative to the Drupal root.
*
* @var string
*/
protected $sitePath;
/**
* The file system service.

Adam G-H
committed
*
* @var \Drupal\Core\File\FileSystemInterface

Adam G-H
committed
*/
protected $fileSystem;
/**
* The stream wrapper manager service.
*
* @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
*/
protected $streamWrapperManager;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Constructs an ExcludedPathsSubscriber.

Adam G-H
committed
*
* @param string $app_root
* The Drupal root.

Adam G-H
committed
* @param string $site_path
* The current site path, relative to the Drupal root.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system service.

Adam G-H
committed
* @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
* The stream wrapper manager service.
* @param \Drupal\Core\Database\Connection $database
* The database connection.

Adam G-H
committed
*/
public function __construct(string $app_root, string $site_path, FileSystemInterface $file_system, StreamWrapperManagerInterface $stream_wrapper_manager, Connection $database) {
$this->appRoot = $app_root;

Adam G-H
committed
$this->sitePath = $site_path;
$this->fileSystem = $file_system;
$this->streamWrapperManager = $stream_wrapper_manager;
$this->database = $database;

Adam G-H
committed
}
/**
* Reacts before staged changes are committed the active directory.
* @param \Drupal\package_manager\Event\PreApplyEvent $event

Adam G-H
committed
* The event object.
*/
public function preApply(PreApplyEvent $event): void {
// Don't copy anything from the staging area's sites/default.
// @todo Make this a lot smarter in https://www.drupal.org/i/3228955.
$event->excludePath('sites/default');

Adam G-H
committed
// If the core-vendor-hardening plugin (used in the legacy-project template)
// is present, it may have written a web.config file into the vendor
// directory. We don't want to copy that.
$event->excludePath('web.config');

Adam G-H
committed
}
/**
* Excludes paths from a staging area before it is created.

Adam G-H
committed
*
* @param \Drupal\package_manager\Event\PreCreateEvent $event

Adam G-H
committed
* The event object.
*/
public function preCreate(PreCreateEvent $event): void {
// Automated test site directories should never be staged.
$event->excludePath('sites/simpletest');
// Windows server configuration files, like web.config, should never be
// staged either. (These can be written in the vendor directory by the
// core-vendor-hardening plugin, which is used in the drupal/legacy-project
// template.)
$event->excludePath('web.config');
if ($public = $this->getFilesPath('public')) {
$event->excludePath($public);

Adam G-H
committed
}
if ($private = $this->getFilesPath('private')) {
$event->excludePath($private);

Adam G-H
committed
}
// Exclude site-specific settings files.

Adam G-H
committed
$settings_files = [
'settings.php',
'settings.local.php',
'services.yml',
];
$default_site = 'sites' . DIRECTORY_SEPARATOR . 'default';

Adam G-H
committed
foreach ($settings_files as $settings_file) {
$event->excludePath($this->sitePath . DIRECTORY_SEPARATOR . $settings_file);
$event->excludePath($default_site . DIRECTORY_SEPARATOR . $settings_file);

Adam G-H
committed
}
// If the database is SQLite, it might be located in the active directory
// and we should not stage it.
if ($this->database->driver() === 'sqlite') {
$options = $this->database->getConnectionOptions();
$database = str_replace($this->appRoot, NULL, $options['database']);
$database = ltrim($database, '/');
$event->excludePath($database);
$event->excludePath("$database-shm");
$event->excludePath("$database-wal");
}

Adam G-H
committed
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
}
/**
* Returns the storage path for a stream wrapper.
*
* This will only work for stream wrappers that extend
* \Drupal\Core\StreamWrapper\LocalStream, which includes the stream wrappers
* for public and private files.
*
* @param string $scheme
* The stream wrapper scheme.
*
* @return string|null
* The storage path for files using the given scheme, relative to the Drupal
* root, or NULL if the stream wrapper does not extend
* \Drupal\Core\StreamWrapper\LocalStream.
*/
private function getFilesPath(string $scheme): ?string {
$wrapper = $this->streamWrapperManager->getViaScheme($scheme);
if ($wrapper instanceof LocalStream) {
return $wrapper->getDirectoryPath();
}
return NULL;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
PreCreateEvent::class => 'preCreate',