View source
<?php
namespace Drupal\config_split\Plugin\ConfigFilter;
use Drupal\config_filter\Plugin\ConfigFilterBase;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Config\DatabaseStorage;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Component\FileSecurity\FileSecurity;
use Symfony\Component\DependencyInjection\ContainerInterface;
class SplitFilter extends ConfigFilterBase implements ContainerFactoryPluginInterface {
use DependencySerializationTrait;
protected $manager;
protected $secondaryStorage;
protected $filterLists;
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigManagerInterface $manager, StorageInterface $secondary = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->manager = $manager;
$this->secondaryStorage = $secondary;
$this->filterLists = new \ArrayObject();
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$config = $container
->get('config.factory')
->get($configuration['config_name']);
$fields = [
'module',
'theme',
'blacklist',
'graylist',
'graylist_dependents',
'graylist_skip_equal',
];
foreach ($fields as $field) {
$configuration[$field] = $config
->get($field);
}
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('config.manager'), self::getSecondaryStorage($config, $container
->get('database')));
}
public function getBlacklist() {
if (!isset($this->filterLists['complete_split'])) {
$this->filterLists['complete_split'] = $this
->calculateBlacklist();
}
return $this->filterLists['complete_split'];
}
public function getGraylist() {
if (!isset($this->filterLists['conditional_split'])) {
$this->filterLists['conditional_split'] = $this
->calculateGraylist();
}
return $this->filterLists['conditional_split'];
}
public function filterRead($name, $data) {
if ($this->secondaryStorage) {
if ($alternative = $this->secondaryStorage
->read($name)) {
return $alternative;
}
}
if ($name != 'core.extension') {
return $data;
}
$modules = isset($this->configuration['module']) ? $this->configuration['module'] : [];
$themes = isset($this->configuration['theme']) ? $this->configuration['theme'] : [];
if ($this->filtered) {
$modules = [];
$themes = [];
$updated = $this->filtered
->read($this->configuration['config_name']);
if (is_array($updated)) {
$modules = isset($updated['module']) ? $updated['module'] : $modules;
$themes = isset($updated['theme']) ? $updated['theme'] : $themes;
}
}
$data['module'] = array_merge($data['module'], $modules);
$data['theme'] = array_merge($data['theme'], $themes);
$sort_modules = $data['module'];
uksort($sort_modules, function ($a, $b) use ($sort_modules) {
if ($sort_modules[$a] != $sort_modules[$b]) {
return $sort_modules[$a] > $sort_modules[$b] ? 1 : -1;
}
return $a > $b ? 1 : -1;
});
$data['module'] = $sort_modules;
return $data;
}
public function filterWrite($name, array $data) {
if (!$this->secondaryStorage) {
throw new \InvalidArgumentException('The split storage has to be set and exist for write operations.');
}
if (in_array($name, $this
->getBlacklist())) {
if ($data) {
$this->secondaryStorage
->write($name, $data);
}
return NULL;
}
elseif (in_array($name, $this
->getGraylist())) {
if (!$this->configuration['graylist_skip_equal'] || !$this->source || $this->source
->read($name) != $data) {
if ($data) {
$this->secondaryStorage
->write($name, $data);
}
if ($this->source) {
return $this->source
->read($name);
}
return NULL;
}
}
if ($this->secondaryStorage
->exists($name)) {
$this->secondaryStorage
->delete($name);
}
if ($name != 'core.extension') {
return $data;
}
$data['module'] = array_diff_key($data['module'], $this->configuration['module']);
$data['theme'] = array_diff_key($data['theme'], $this->configuration['theme']);
return $data;
}
public function filterWriteEmptyIsDelete($name) {
return $name != 'core.extension';
}
public function filterExists($name, $exists) {
if (!$exists && $this->secondaryStorage) {
$exists = $this->secondaryStorage
->exists($name);
}
return $exists;
}
public function filterDelete($name, $delete) {
if ($delete && $this->secondaryStorage && $this->secondaryStorage
->exists($name)) {
$this->secondaryStorage
->delete($name);
}
if (in_array($name, $this
->getGraylist()) && !in_array($name, $this
->getBlacklist())) {
return FALSE;
}
return $delete;
}
public function filterReadMultiple(array $names, array $data) {
if ($this->secondaryStorage) {
$data = array_merge($data, $this->secondaryStorage
->readMultiple($names));
}
if (in_array('core.extension', $names)) {
$data['core.extension'] = $this
->filterRead('core.extension', $data['core.extension']);
}
return $data;
}
public function filterListAll($prefix, array $data) {
if ($this->secondaryStorage) {
$data = array_unique(array_merge($data, $this->secondaryStorage
->listAll($prefix)));
}
return $data;
}
public function filterDeleteAll($prefix, $delete) {
if ($delete && $this->secondaryStorage) {
try {
$this->secondaryStorage
->deleteAll($prefix);
} catch (\UnexpectedValueException $exception) {
}
}
if (!empty($this
->getGraylist())) {
return FALSE;
}
return $delete;
}
public function filterCreateCollection($collection) {
if ($this->secondaryStorage) {
$filter = new static($this->configuration, $this->pluginId, $this->pluginDefinition, $this->manager, $this->secondaryStorage
->createCollection($collection));
$filter->filterLists = $this->filterLists;
return $filter;
}
return $this;
}
public function filterGetAllCollectionNames(array $collections) {
if ($this->secondaryStorage) {
$collections = array_unique(array_merge($collections, $this->secondaryStorage
->getAllCollectionNames()));
}
return $collections;
}
protected function calculateBlacklist() {
$blacklist = $this->configuration['blacklist'];
$modules = array_keys($this->configuration['module']);
if ($modules) {
$blacklist = array_merge($blacklist, array_keys($this->manager
->findConfigEntityDependents('module', $modules)));
}
$themes = array_keys($this->configuration['theme']);
if ($themes) {
$blacklist = array_merge($blacklist, array_keys($this->manager
->findConfigEntityDependents('theme', $themes)));
}
$extensions = array_merge([], $modules, $themes);
if (empty($blacklist) && empty($extensions)) {
return [];
}
$blacklist = array_filter($this->manager
->getConfigFactory()
->listAll(), function ($name) use ($extensions, $blacklist) {
foreach ($extensions as $extension) {
if (strpos($name, $extension . '.') === 0) {
return TRUE;
}
}
return self::inFilterList($name, $blacklist);
});
sort($blacklist);
$blacklist = array_unique(array_merge($blacklist, array_keys($this->manager
->findConfigEntityDependents('config', $blacklist))));
return array_diff($blacklist, $this
->getGraylist());
}
protected function calculateGraylist() {
$graylist = $this->configuration['graylist'];
if (empty($graylist)) {
return [];
}
$graylist = array_filter($this->manager
->getConfigFactory()
->listAll(), function ($name) use ($graylist) {
return self::inFilterList($name, $graylist);
});
sort($graylist);
if ($this->configuration['graylist_dependents']) {
$graylist = array_unique(array_merge($graylist, array_keys($this->manager
->findConfigEntityDependents('config', $graylist))));
}
return $graylist;
}
protected static function inFilterList($name, array $list) {
$list = array_map(function ($line) {
return str_replace('\\*', '.*', preg_quote($line, '/'));
}, $list);
foreach ($list as $line) {
if (preg_match('/^' . $line . '$/', $name)) {
return TRUE;
}
}
return FALSE;
}
protected static function getSecondaryStorage(ImmutableConfig $config, Connection $connection) {
if ($directory = $config
->get('folder')) {
if (!is_dir($directory)) {
@mkdir($directory, 0777, TRUE);
}
if (file_exists($directory) && is_writable($directory)) {
$htaccess_path = rtrim($directory, '/\\') . '/.htaccess';
if (!file_exists($htaccess_path)) {
file_put_contents($htaccess_path, FileSecurity::htaccessLines(TRUE));
@chmod($htaccess_path, 0444);
}
}
if (file_exists($directory) || strpos($directory, 'vfs://') === 0) {
return new FileStorage($directory);
}
return NULL;
}
return new DatabaseStorage($connection, $connection
->escapeTable(strtr($config
->getName(), [
'.' => '_',
])));
}
}