Issue #3016429 by bircher, mpotter, alexpott, johndevman, borisson_, Upchuk, larowlan: Add a config storage copy utility trait and fix ConfigManager::createSnapshot
parent
a916e4d4fa
commit
21c3504993
|
@ -22,6 +22,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|||
class ConfigManager implements ConfigManagerInterface {
|
||||
use StringTranslationTrait;
|
||||
use DeprecatedServicePropertyTrait;
|
||||
use StorageCopyTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -207,23 +208,7 @@ class ConfigManager implements ConfigManagerInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function createSnapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
|
||||
// Empty the snapshot of all configuration.
|
||||
$snapshot_storage->deleteAll();
|
||||
foreach ($snapshot_storage->getAllCollectionNames() as $collection) {
|
||||
$snapshot_collection = $snapshot_storage->createCollection($collection);
|
||||
$snapshot_collection->deleteAll();
|
||||
}
|
||||
foreach ($source_storage->listAll() as $name) {
|
||||
$snapshot_storage->write($name, $source_storage->read($name));
|
||||
}
|
||||
// Copy collections as well.
|
||||
foreach ($source_storage->getAllCollectionNames() as $collection) {
|
||||
$source_collection = $source_storage->createCollection($collection);
|
||||
$snapshot_collection = $snapshot_storage->createCollection($collection);
|
||||
foreach ($source_collection->listAll() as $name) {
|
||||
$snapshot_collection->write($name, $source_collection->read($name));
|
||||
}
|
||||
}
|
||||
self::replaceStorageContents($source_storage, $snapshot_storage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
/**
|
||||
* Utility trait to copy configuration from one storage to another.
|
||||
*/
|
||||
trait StorageCopyTrait {
|
||||
|
||||
/**
|
||||
* Copy the configuration from one storage to another and remove stale items.
|
||||
*
|
||||
* This method empties target storage and copies all collections from source.
|
||||
* Configuration is only copied and not imported, should not be used
|
||||
* with the active storage as the target.
|
||||
*
|
||||
* @param \Drupal\Core\Config\StorageInterface $source
|
||||
* The configuration storage to copy from.
|
||||
* @param \Drupal\Core\Config\StorageInterface $target
|
||||
* The configuration storage to copy to.
|
||||
*/
|
||||
protected static function replaceStorageContents(StorageInterface $source, StorageInterface &$target) {
|
||||
// Make sure there is no stale configuration in the target storage.
|
||||
foreach (array_merge([StorageInterface::DEFAULT_COLLECTION], $target->getAllCollectionNames()) as $collection) {
|
||||
$target->createCollection($collection)->deleteAll();
|
||||
}
|
||||
|
||||
// Copy all the configuration from all the collections.
|
||||
foreach (array_merge([StorageInterface::DEFAULT_COLLECTION], $source->getAllCollectionNames()) as $collection) {
|
||||
$source_collection = $source->createCollection($collection);
|
||||
$target_collection = $target->createCollection($collection);
|
||||
foreach ($source_collection->listAll() as $name) {
|
||||
$target_collection->write($name, $source_collection->read($name));
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the target is set to the same collection as the source.
|
||||
$target = $target->createCollection($source->getCollectionName());
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace Drupal\Tests;
|
|||
|
||||
use Drupal\Core\Config\ConfigImporter;
|
||||
use Drupal\Core\Config\StorageComparer;
|
||||
use Drupal\Core\Config\StorageCopyTrait;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
|
||||
/**
|
||||
|
@ -11,6 +12,8 @@ use Drupal\Core\Config\StorageInterface;
|
|||
*/
|
||||
trait ConfigTestTrait {
|
||||
|
||||
use StorageCopyTrait;
|
||||
|
||||
/**
|
||||
* Returns a ConfigImporter object to import test configuration.
|
||||
*
|
||||
|
@ -49,10 +52,7 @@ trait ConfigTestTrait {
|
|||
* The target config storage service.
|
||||
*/
|
||||
protected function copyConfig(StorageInterface $source_storage, StorageInterface $target_storage) {
|
||||
$target_storage->deleteAll();
|
||||
foreach ($source_storage->listAll() as $name) {
|
||||
$target_storage->write($name, $source_storage->read($name));
|
||||
}
|
||||
static::replaceStorageContents($source_storage, $target_storage);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\Core\Config;
|
||||
|
||||
use Drupal\Core\Config\MemoryStorage;
|
||||
use Drupal\Core\Config\StorageCopyTrait;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Config\StorageCopyTrait
|
||||
* @group Config
|
||||
*/
|
||||
class StorageCopyTraitTest extends UnitTestCase {
|
||||
|
||||
use StorageCopyTrait;
|
||||
|
||||
/**
|
||||
* @covers ::replaceStorageContents
|
||||
*
|
||||
* @dataProvider providerTestReplaceStorageContents
|
||||
*/
|
||||
public function testReplaceStorageContents($source_collections, $target_collections) {
|
||||
$source = new MemoryStorage();
|
||||
$target = new MemoryStorage();
|
||||
// Empty the storage should be the same.
|
||||
$this->assertArrayEquals(self::toArray($source), self::toArray($target));
|
||||
|
||||
// When the source is populated, they are not the same any more.
|
||||
$this->generateRandomData($source, $source_collections);
|
||||
$this->assertNotEquals(self::toArray($source), self::toArray($target));
|
||||
|
||||
// When the target is filled with random data they are also not the same.
|
||||
$this->generateRandomData($target, $target_collections);
|
||||
$this->assertNotEquals(self::toArray($source), self::toArray($target));
|
||||
|
||||
// Set the active collection to a random one on both source and target.
|
||||
if ($source_collections) {
|
||||
$collections = $source->getAllCollectionNames();
|
||||
$source = $source->createCollection($collections[array_rand($collections)]);
|
||||
}
|
||||
if ($target_collections) {
|
||||
$collections = $target->getAllCollectionNames();
|
||||
$target = $target->createCollection($collections[array_rand($collections)]);
|
||||
}
|
||||
|
||||
$source_data = self::toArray($source);
|
||||
$source_name = $source->getCollectionName();
|
||||
|
||||
// After copying they are the same, this asserts that items not present
|
||||
// in the source get removed from the target.
|
||||
self::replaceStorageContents($source, $target);
|
||||
$this->assertArrayEquals($source_data, self::toArray($target));
|
||||
// Assert that the copy method did indeed not change the source.
|
||||
$this->assertArrayEquals($source_data, self::toArray($source));
|
||||
|
||||
// Assert that the active collection is the same as the original source.
|
||||
$this->assertEquals($source_name, $source->getCollectionName());
|
||||
$this->assertEquals($source_name, $target->getCollectionName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for testCheckRequirements().
|
||||
*/
|
||||
public function providerTestReplaceStorageContents() {
|
||||
$data = [];
|
||||
$data[] = [TRUE, TRUE];
|
||||
$data[] = [TRUE, FALSE];
|
||||
$data[] = [FALSE, TRUE];
|
||||
$data[] = [FALSE, FALSE];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the protected config data out of a MemoryStorage.
|
||||
*
|
||||
* @param \Drupal\Core\Config\MemoryStorage $storage
|
||||
* The config storage to extract the data from.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function toArray(MemoryStorage $storage) {
|
||||
$reflection = new \ReflectionObject($storage);
|
||||
$property = $reflection->getProperty('config');
|
||||
$property->setAccessible(TRUE);
|
||||
|
||||
return $property->getValue($storage)->getArrayCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random data in a config storage.
|
||||
*
|
||||
* @param \Drupal\Core\Config\StorageInterface $storage
|
||||
* The storage to populate with random data.
|
||||
* @param bool $collections
|
||||
* Add random collections or not.
|
||||
*/
|
||||
protected function generateRandomData(StorageInterface $storage, $collections = TRUE) {
|
||||
$generator = $this->getRandomGenerator();
|
||||
for ($i = 0; $i < rand(2, 10); $i++) {
|
||||
$storage->write($this->randomMachineName(), (array) $generator->object());
|
||||
}
|
||||
if ($collections) {
|
||||
for ($i = 0; $i < rand(1, 5); $i++) {
|
||||
$collection = $storage->createCollection($this->randomMachineName());
|
||||
for ($i = 0; $i < rand(2, 10); $i++) {
|
||||
$collection->write($this->randomMachineName(), (array) $generator->object());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue