diff -u b/core/lib/Drupal/Component/Scaffold/Handler.php b/core/lib/Drupal/Component/Scaffold/Handler.php
--- b/core/lib/Drupal/Component/Scaffold/Handler.php
+++ b/core/lib/Drupal/Component/Scaffold/Handler.php
@@ -154,16 +154,15 @@
// them.
$file_mappings = $this->getFileMappingsFromPackages($allowed_packages);
- // Analyze the list of file mappings, and determine which take priority.
$location_replacements = $this->manageOptions->getLocationReplacements();
- $scaffold_files = ScaffoldFileCollection::create($file_mappings, $location_replacements);
- $scaffold_results = [];
- // Process all of the files that were collated one package at a time.
- iterator_apply(
- $scaffold_files,
- [ScaffoldFileCollection::class, 'process'],
- [$scaffold_files, $this->io, $this->manageOptions->getOptions(), &$scaffold_results]
- );
+ $scaffold_options = $this->manageOptions->getOptions();
+
+ // Create a collection of scaffolded files to process. This determines which
+ // take priority and which are conjoined.
+ $scaffold_files = new ScaffoldFileCollection($file_mappings, $location_replacements);
+
+ // Process the list of scaffolded files.
+ $scaffold_results = ScaffoldFileCollection::process($scaffold_files, $this->io, $scaffold_options);
// Generate an autoload file in the document root that includes the
// autoload.php file in the vendor directory, wherever that is. Drupal
@@ -175,7 +174,7 @@
// Add the managed scaffold files to .gitignore if applicable.
$gitIgnoreManager = new ManageGitIgnore($this->io, getcwd());
- $gitIgnoreManager->manageIgnored($scaffold_results, $this->manageOptions->getOptions());
+ $gitIgnoreManager->manageIgnored($scaffold_results, $scaffold_options);
// Call post-scaffold scripts.
$dispatcher->dispatch(self::POST_COMPOSER_SCAFFOLD_CMD);
diff -u b/core/lib/Drupal/Component/Scaffold/Operations/ScaffoldFileCollection.php b/core/lib/Drupal/Component/Scaffold/Operations/ScaffoldFileCollection.php
--- b/core/lib/Drupal/Component/Scaffold/Operations/ScaffoldFileCollection.php
+++ b/core/lib/Drupal/Component/Scaffold/Operations/ScaffoldFileCollection.php
@@ -7,44 +7,38 @@
use Drupal\Component\Scaffold\ScaffoldFileInfo;
use Drupal\Component\Scaffold\ScaffoldFilePath;
use Drupal\Component\Scaffold\ScaffoldOptions;
-use RecursiveIterator;
/**
* Collection of scaffold files.
*/
-final class ScaffoldFileCollection {
+class ScaffoldFileCollection implements \IteratorAggregate {
/**
- * ScaffoldFileCollection constructor.
+ * 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\Component\Scaffold\ScaffoldFileInfo[][]
*/
- private function __construct() {
- // This class only provides static methods.
- }
+ protected $scaffoldFilesByProject = [];
/**
* ScaffoldFileCollection constructor.
*
* @param array $file_mappings
- * An multidimensional array of file mappings, as returned by
- * self::getFileMappingsFromPackages().
+ * A multidimensional array of file mappings.
* @param \Drupal\Component\Scaffold\Interpolator $location_replacements
* An object with the location mappings (e.g. [web-root]).
- *
- * @return \RecursiveArrayIterator
- * An iterator on a multi-dimensional array of ScaffoldFileInfo objects
- * keyed by the project and the destination path.
- *
- * @see \Drupal\Component\Scaffold\ScaffoldFileInfo
*/
- public static function create(array $file_mappings, Interpolator $location_replacements) {
+ 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 = [];
- // Collection of all destination paths to be scaffolded by project.
- $scaffoldFilesByProject = [];
-
+ // 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);
@@ -59,45 +53,49 @@
if ($op instanceof ConjoinableInterface) {
$op = new ConjunctionOp($previous_scaffold_file->op(), $op);
// Remove the previous file so we only do the operation once.
- unset($scaffoldFilesByProject[$previous_scaffold_file->packageName()][$destination_rel_path]);
+ unset($this->scaffoldFilesByProject[$previous_scaffold_file->packageName()][$destination_rel_path]);
}
else {
$message = " - Skip [dest-rel-path]: overridden in {$package_name}";
- $scaffoldFilesByProject[$previous_scaffold_file->packageName()][$destination_rel_path] = new ScaffoldFileInfo($destination, new SkipOp($message));
+ $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;
- $scaffoldFilesByProject[$package_name][$destination_rel_path] = $scaffold_file;
+ $this->scaffoldFilesByProject[$package_name][$destination_rel_path] = $scaffold_file;
}
}
- return new \RecursiveArrayIterator($scaffoldFilesByProject, \RecursiveArrayIterator::CHILD_ARRAYS_ONLY);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIterator() {
+ return new \RecursiveArrayIterator($this->scaffoldFilesByProject, \RecursiveArrayIterator::CHILD_ARRAYS_ONLY);
}
/**
* Processes the iterator created by ScaffoldFileCollection::create().
*
- * @param \RecursiveIterator $iterator
+ * @param \Drupal\Component\Scaffold\Operations\ScaffoldFileCollection $collection
* The iterator to process.
* @param \Composer\IO\IOInterface $io
* The Composer IO object.
* @param \Drupal\Component\Scaffold\ScaffoldOptions $scaffold_options
* The scaffold options.
- * @param \Drupal\Component\Scaffold\Operations\ScaffoldResult[] $results
- * The results array, passed by-reference and is populated by this method.
+ *
+ * @return \Drupal\Component\Scaffold\Operations\ScaffoldResult[]
+ * The results array.
*/
- public static function process(RecursiveIterator $iterator, IOInterface $io, ScaffoldOptions $scaffold_options, array &$results) {
- while ($iterator->valid()) {
- if ($iterator->hasChildren()) {
- $io->write("Scaffolding files for {$iterator->key()}:");
- static::process($iterator->getChildren(), $io, $scaffold_options, $results);
- }
- else {
- $scaffold_file = $iterator->current();
+ public static function process(ScaffoldFileCollection $collection, IOInterface $io, ScaffoldOptions $scaffold_options) {
+ $results = [];
+ foreach ($collection as $project_name => $scaffold_files) {
+ $io->write("Scaffolding files for {$project_name}:");
+ foreach ($scaffold_files as $scaffold_file) {
$results[$scaffold_file->destination()->relativePath()] = $scaffold_file->process($io, $scaffold_options);
}
- $iterator->next();
}
+ return $results;
}
}
diff -u b/core/tests/Drupal/Tests/Component/Scaffold/Integration/ScaffoldFileCollectionTest.php b/core/tests/Drupal/Tests/Component/Scaffold/Integration/ScaffoldFileCollectionTest.php
--- b/core/tests/Drupal/Tests/Component/Scaffold/Integration/ScaffoldFileCollectionTest.php
+++ b/core/tests/Drupal/Tests/Component/Scaffold/Integration/ScaffoldFileCollectionTest.php
@@ -16,7 +16,7 @@
class ScaffoldFileCollectionTest extends TestCase {
/**
- * @covers ::create
+ * @covers ::__construct
*/
public function testCreate() {
$fixtures = new Fixtures();
@@ -36,7 +36,7 @@
'[web-root]/robots.txt' => $fixtures->appendOp('drupal-drupal-test-append', 'append-to-robots.txt'),
],
];
- $sut = ScaffoldFileCollection::create($scaffold_file_fixtures, $locationReplacements);
+ $sut = new ScaffoldFileCollection($scaffold_file_fixtures, $locationReplacements);
$resolved_file_mappings = iterator_to_array($sut);
// Confirm that the keys of the output are the same as the keys of the
// input.