Newer
Older
<?php

omkar podey
committed
declare(strict_types = 1);
namespace Drupal\package_manager\Event;

Kunal Sachdev
committed
use Drupal\package_manager\StageBase;

Wim Leers
committed
use Drupal\package_manager\PathLocator;

Adam G-H
committed
use PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface;

Ted Bowman
committed
use PhpTuf\ComposerStager\API\Path\Factory\PathListFactoryInterface;

Adam G-H
committed
use PhpTuf\ComposerStager\API\Path\Value\PathListInterface;
/**
* Defines an event that collects paths to exclude.
*
* These paths are excluded by Composer Stager and are never copied into the
* stage directory from the active directory, or vice-versa.
*/

Wim Leers
committed
final class CollectPathsToExcludeEvent extends StageEvent implements PathListInterface {
/**

Wim Leers
committed
* Constructs a CollectPathsToExcludeEvent object.
*
* @param \Drupal\package_manager\StageBase $stage
* The stage which fired this event.
* @param \Drupal\package_manager\PathLocator $pathLocator
* The path locator service.

Adam G-H
committed
* @param \PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface $pathFactory

Wim Leers
committed
* The path factory service.

Ted Bowman
committed
* @param \PhpTuf\ComposerStager\API\Path\Value\PathListInterface|null $pathList
* (optional) The list of paths to exclude.
*/

Wim Leers
committed
public function __construct(
StageBase $stage,

Lucas Hedding
committed
private readonly PathLocator $pathLocator,

Ted Bowman
committed
private readonly PathFactoryInterface $pathFactory,
private ?PathListInterface $pathList = NULL,

Wim Leers
committed
) {
parent::__construct($stage);

Ted Bowman
committed
$this->pathList ??= \Drupal::service(PathListFactoryInterface::class)
->create();
}
/**
* {@inheritdoc}
*/

Adam G-H
committed
public function add(string ...$paths): void {
$this->pathList->add(...$paths);
}
/**
* {@inheritdoc}
*/
public function getAll(): array {

Ted Bowman
committed
return array_unique($this->pathList->getAll());
}

Wim Leers
committed
/**
* Flags paths to be ignored, relative to the web root.
*
* This should only be used for paths that, if they exist at all, are
* *guaranteed* to exist within the web root.
*
* @param string[] $paths
* The paths to ignore. These should be relative to the web root, and will
* be made relative to the project root.
*/
public function addPathsRelativeToWebRoot(array $paths): void {
$web_root = $this->pathLocator->getWebRoot();
if ($web_root) {
$web_root .= '/';
}
foreach ($paths as $path) {
// Make the path relative to the project root by prefixing the web root.

Adam G-H
committed
$this->add($web_root . $path);

Wim Leers
committed
}
}
/**
* Flags paths to be ignored, relative to the project root.
*
* @param string[] $paths
* The paths to ignore. Absolute paths will be made relative to the project
* root; relative paths will be assumed to already be relative to the
* project root, and ignored as given.
*
* @throws \LogicException
* If any of the given paths are absolute, but not inside the project root.

Wim Leers
committed
*/
public function addPathsRelativeToProjectRoot(array $paths): void {
$project_root = $this->pathLocator->getProjectRoot();
foreach ($paths as $path) {
if ($this->pathFactory->create($path)->isAbsolute()) {
if (!str_starts_with($path, $project_root)) {
throw new \LogicException("$path is not inside the project root: $project_root.");
}
}
// Make absolute paths relative to the project root.
$path = str_replace($project_root, '', $path);
$path = ltrim($path, '/');

Adam G-H
committed
$this->add($path);

Wim Leers
committed
}
}
/**
* Finds all directories in the project root matching the given name.
*
* @param string $directory_name
* The directory name to scan for.
*
* @return string[]
* All discovered absolute paths matching the given directory name.
*/
public function scanForDirectoriesByName(string $directory_name): array {
$flags = \FilesystemIterator::UNIX_PATHS;
$flags |= \FilesystemIterator::CURRENT_AS_SELF;
$directories_tree = new \RecursiveDirectoryIterator($this->pathLocator->getProjectRoot(), $flags);
$filtered_directories = new \RecursiveIteratorIterator($directories_tree, \RecursiveIteratorIterator::SELF_FIRST);
$matched_directories = new \CallbackFilterIterator($filtered_directories,
fn (\RecursiveDirectoryIterator $current) => $current->isDir() && $current->getFilename() === $directory_name
);
return array_keys(iterator_to_array($matched_directories));
}