Skip to content

Commit bbb8898

Browse files
committed
Service
1 parent 60ca9a9 commit bbb8898

File tree

4 files changed

+276
-151
lines changed

4 files changed

+276
-151
lines changed

config_helper.services.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
services:
2+
Drupal\config_helper\ConfigHelper:
3+
arguments:
4+
- '@module_handler'
5+
- '@config.factory'
6+
- '@file_system'

scripts/code-analysis

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ rm -fr "$drupal_dir/$module_path"
2727

2828
git config --global --add safe.directory /app
2929
# Create directories
30-
git ls-files -z | xargs --null -I {} --verbose bash -c 'mkdir -p '"$drupal_dir/$module_path/"'$(dirname {})'
30+
git ls-files -z | xargs --null -I {} bash -c 'mkdir -p '"$drupal_dir/$module_path/"'$(dirname {})'
3131
# Copy files
3232
git ls-files -z | xargs --null -I {} cp {} "$drupal_dir/$module_path/{}"
3333

src/ConfigHelper.php

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
<?php
2+
3+
namespace Drupal\config_helper;
4+
5+
use Drupal\Core\Config\ConfigFactoryInterface;
6+
use Drupal\Core\Extension\ModuleHandlerInterface;
7+
use Drupal\Core\File\FileSystemInterface;
8+
use Drupal\Core\Serialization\Yaml;
9+
use Psr\Log\LoggerAwareTrait;
10+
use Psr\Log\NullLogger;
11+
use Symfony\Component\Console\Exception\RuntimeException;
12+
13+
/**
14+
* Config helper.
15+
*/
16+
class ConfigHelper {
17+
use LoggerAwareTrait;
18+
19+
/**
20+
* Contructor.
21+
*/
22+
public function __construct(
23+
private readonly ModuleHandlerInterface $moduleHandler,
24+
private readonly ConfigFactoryInterface $configFactory,
25+
private readonly FileSystemInterface $fileSystem,
26+
) {
27+
$this->setLogger(new NullLogger());
28+
}
29+
30+
/**
31+
* Add enforced module dependency.
32+
*/
33+
public function addEnforcedDependency(
34+
string $module,
35+
array $configNames
36+
): void {
37+
foreach ($configNames as $name) {
38+
$this->logger->info(sprintf('Config name: %s', $name));
39+
40+
$config = $this->configFactory->getEditable($name);
41+
42+
$data = $config->getRawData();
43+
$data['dependencies']['enforced']['module'][] = $module;
44+
$data['dependencies']['enforced']['module'] = array_unique($data['dependencies']['enforced']['module']);
45+
sort($data['dependencies']['enforced']['module']);
46+
$config->setData($data);
47+
48+
$config->save();
49+
}
50+
}
51+
52+
/**
53+
* Remove enforced module dependency.
54+
*/
55+
public function removeEnforcedDependency(
56+
string $module,
57+
array $configNames
58+
): void {
59+
foreach ($configNames as $name) {
60+
$this->logger->info(sprintf('Config name: %s', $name));
61+
62+
$config = $this->configFactory->getEditable($name);
63+
64+
$data = $config->getRawData();
65+
if (isset($data['dependencies']['enforced']['module'])) {
66+
$data['dependencies']['enforced']['module'] = array_diff($data['dependencies']['enforced']['module'], [$module]);
67+
sort($data['dependencies']['enforced']['module']);
68+
if (empty($data['dependencies']['enforced']['module'])) {
69+
unset($data['dependencies']['enforced']['module']);
70+
}
71+
if (empty($data['dependencies']['enforced'])) {
72+
unset($data['dependencies']['enforced']);
73+
}
74+
if (empty($data['dependencies'])) {
75+
unset($data['dependencies']);
76+
}
77+
$config->setData($data);
78+
$config->save();
79+
}
80+
}
81+
}
82+
83+
/**
84+
* Write module config.
85+
*/
86+
public function writeModuleConfig(
87+
string $module,
88+
mixed $optional,
89+
array $configNames
90+
): void {
91+
$moduleConfigPath = $this->getModuleConfigPath($module, $optional);
92+
if (!is_dir($moduleConfigPath)) {
93+
$this->fileSystem->mkdir($moduleConfigPath, 0755, TRUE);
94+
}
95+
96+
foreach ($configNames as $name) {
97+
$this->logger->info($name);
98+
99+
$filename = $name . '.yml';
100+
$destination = $moduleConfigPath . '/' . $filename;
101+
$config = $this->configFactory->get($name)->getRawData();
102+
// @see https://www.drupal.org/node/2087879#s-exporting-configuration
103+
unset($config['uuid'], $config['_core']);
104+
105+
file_put_contents($destination, Yaml::encode($config));
106+
}
107+
}
108+
109+
/**
110+
* Rename config.
111+
*/
112+
public function renameConfig(
113+
string $from,
114+
string $to,
115+
array $configNames,
116+
bool $regex = FALSE
117+
): void {
118+
$replacer = $regex
119+
? static fn (string $subject) => preg_replace($from, $to, $subject)
120+
: static fn (string $subject) => str_replace($from, $to, $subject);
121+
122+
foreach ($configNames as $name) {
123+
$config = $this->configFactory->getEditable($name);
124+
$data = $config->getRawData();
125+
$newData = $this->replaceKeysAndValues($replacer, $data);
126+
if ($newData !== $data) {
127+
$config->setData($newData);
128+
$this->logger->info(sprintf('Saving updated config %s', $name));
129+
$config->save();
130+
}
131+
132+
$newName = $replacer($name);
133+
if ($newName !== $name) {
134+
$this->logger->info(sprintf('Renaming config %s to %s', $name, $newName));
135+
$this->configFactory->rename($name, $newName);
136+
}
137+
}
138+
}
139+
140+
/**
141+
* Get config names matching patterns.
142+
*/
143+
public function getConfigNames(array $patterns): array {
144+
$names = $this->configFactory->listAll();
145+
if (empty($patterns)) {
146+
return $names;
147+
}
148+
149+
$configNames = [];
150+
foreach ($patterns as $pattern) {
151+
$chunk = array_filter(
152+
$names,
153+
// phpcs:disable Drupal.Functions.DiscouragedFunctions.Discouraged -- https://www.php.net/manual/en/function.fnmatch.php#refsect1-function.fnmatch-notes
154+
static fn ($name) => fnmatch($pattern, $name),
155+
);
156+
if (empty($chunk)) {
157+
throw new RuntimeException(sprintf('No config matches %s', var_export($pattern, TRUE)));
158+
}
159+
$configNames[] = $chunk;
160+
}
161+
162+
$configNames = array_unique(array_merge(...$configNames));
163+
sort($configNames);
164+
165+
return $configNames;
166+
}
167+
168+
/**
169+
* Get config names for a module.
170+
*/
171+
public function getModuleConfigNames(string $module): array {
172+
return $this->getConfigNames(['*.' . $module . '.*']);
173+
}
174+
175+
/**
176+
* Get names of config that has an enforced dependency on a module.
177+
*/
178+
public function getEnforcedModuleConfigNames(string $module): array {
179+
$configNames = array_values(
180+
array_filter(
181+
$this->configFactory->listAll(),
182+
function ($name) use ($module) {
183+
$config = $this->configFactory->get($name)->getRawData();
184+
$list = $config['dependencies']['enforced']['module'] ?? NULL;
185+
186+
return is_array($list) && in_array($module, $list, TRUE);
187+
}
188+
)
189+
);
190+
191+
if (empty($configNames)) {
192+
throw new RuntimeException(sprintf('No config has an enforced dependency on "%s".', $module));
193+
}
194+
195+
return $configNames;
196+
}
197+
198+
/**
199+
* Check if a module exists.
200+
*/
201+
public function moduleExists(string $module): bool {
202+
return $this->moduleHandler->moduleExists($module);
203+
}
204+
205+
/**
206+
* Get module config path.
207+
*/
208+
public function getModuleConfigPath(string $module, bool $optional): string {
209+
$modulePath = $this->moduleHandler->getModule($module)->getPath();
210+
211+
return $modulePath . '/config/' . ($optional ? 'optional' : 'install');
212+
}
213+
214+
/**
215+
* Replace in keys and values.
216+
*
217+
* @see https://stackoverflow.com/a/29619470
218+
*/
219+
private function replaceKeysAndValues(
220+
callable $replacer,
221+
array $input
222+
): array {
223+
$return = [];
224+
foreach ($input as $key => $value) {
225+
$key = $replacer($key);
226+
227+
if (is_array($value)) {
228+
$value = $this->replaceKeysAndValues($replacer, $value);
229+
}
230+
elseif (is_string($value)) {
231+
$value = $replacer($value);
232+
}
233+
234+
$return[$key] = $value;
235+
}
236+
237+
return $return;
238+
}
239+
240+
}

0 commit comments

Comments
 (0)