drupal/composer/Plugin/Scaffold/Operations/ScaffoldFileCollection.php

99 lines
4.0 KiB
PHP

<?php
namespace Drupal\Composer\Plugin\Scaffold\Operations;
use Composer\IO\IOInterface;
use Drupal\Composer\Plugin\Scaffold\Interpolator;
use Drupal\Composer\Plugin\Scaffold\ScaffoldFileInfo;
use Drupal\Composer\Plugin\Scaffold\ScaffoldFilePath;
use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
/**
* Collection of scaffold files.
*/
class ScaffoldFileCollection implements \IteratorAggregate {
/**
* Nested list of all scaffold files.
*
* The top level array maps from the package name to the collection of
* scaffold files provided by that package. Each collection of scaffold files
* is keyed by destination path.
*
* @var \Drupal\Composer\Plugin\Scaffold\ScaffoldFileInfo[][]
*/
protected $scaffoldFilesByProject = [];
/**
* ScaffoldFileCollection constructor.
*
* @param array $file_mappings
* A multidimensional array of file mappings.
* @param \Drupal\Composer\Plugin\Scaffold\Interpolator $location_replacements
* An object with the location mappings (e.g. [web-root]).
*/
public function __construct(array $file_mappings, Interpolator $location_replacements) {
// Collection of all destination paths to be scaffolded. Used to determine
// when two project scaffold the same file and we have to skip or use a
// ConjunctionOp.
$scaffoldFiles = [];
// Build the list of ScaffoldFileInfo objects by project.
foreach ($file_mappings as $package_name => $package_file_mappings) {
foreach ($package_file_mappings as $destination_rel_path => $op) {
$destination = ScaffoldFilePath::destinationPath($package_name, $destination_rel_path, $location_replacements);
// If there was already a scaffolding operation happening at this path,
// and the new operation is Conjoinable, then use a ConjunctionOp to
// join together both operations. This will cause both operations to
// run, one after the other. At the moment, only AppendOp is
// conjoinable; all other operations simply replace anything at the same
// path.
if (isset($scaffoldFiles[$destination_rel_path])) {
$previous_scaffold_file = $scaffoldFiles[$destination_rel_path];
if ($op instanceof ConjoinableInterface) {
$op = new ConjunctionOp($previous_scaffold_file->op(), $op);
}
// Remove the previous op so we only touch the destination once.
$message = " - Skip <info>[dest-rel-path]</info>: overridden in <comment>{$package_name}</comment>";
$this->scaffoldFilesByProject[$previous_scaffold_file->packageName()][$destination_rel_path] = new ScaffoldFileInfo($destination, new SkipOp($message));
}
$scaffold_file = new ScaffoldFileInfo($destination, $op);
$scaffoldFiles[$destination_rel_path] = $scaffold_file;
$this->scaffoldFilesByProject[$package_name][$destination_rel_path] = $scaffold_file;
}
}
}
/**
* {@inheritdoc}
*/
public function getIterator() {
return new \RecursiveArrayIterator($this->scaffoldFilesByProject, \RecursiveArrayIterator::CHILD_ARRAYS_ONLY);
}
/**
* Processes the iterator created by ScaffoldFileCollection::create().
*
* @param \Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection $collection
* The iterator to process.
* @param \Composer\IO\IOInterface $io
* The Composer IO object.
* @param \Drupal\Composer\Plugin\Scaffold\ScaffoldOptions $scaffold_options
* The scaffold options.
*
* @return \Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldResult[]
* The results array.
*/
public static function process(ScaffoldFileCollection $collection, IOInterface $io, ScaffoldOptions $scaffold_options) {
$results = [];
foreach ($collection as $project_name => $scaffold_files) {
$io->write("Scaffolding files for <comment>{$project_name}</comment>:");
foreach ($scaffold_files as $scaffold_file) {
$results[$scaffold_file->destination()->relativePath()] = $scaffold_file->process($io, $scaffold_options);
}
}
return $results;
}
}