feat: lit/divi-variables-set warnt vor Verwendungen in Presets und beim Archivieren verwendeter Variablen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
d7a8b85f8d
commit
fef964bb7a
@@ -10,6 +10,7 @@ use LIT\MCP\Abilities\Ability;
|
|||||||
use LIT\MCP\Abilities\Annotations;
|
use LIT\MCP\Abilities\Annotations;
|
||||||
use LIT\MCP\Abilities\Errors;
|
use LIT\MCP\Abilities\Errors;
|
||||||
use LIT\MCP\Integrations\Divi\Library\GlobalUsages;
|
use LIT\MCP\Integrations\Divi\Library\GlobalUsages;
|
||||||
|
use LIT\MCP\Integrations\Divi\Library\UsageReport;
|
||||||
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
use LIT\MCP\Integrations\Divi\Release\DiviFeature;
|
||||||
use LIT\MCP\Integrations\Divi\Release\RequiresDiviFeatures;
|
use LIT\MCP\Integrations\Divi\Release\RequiresDiviFeatures;
|
||||||
use WP_Error;
|
use WP_Error;
|
||||||
@@ -22,7 +23,7 @@ defined('ABSPATH') || exit;
|
|||||||
* value. Variables are never deleted – Divi refuses an inventory that lacks a stored ID (V1) –, only archived (order
|
* value. Variables are never deleted – Divi refuses an inventory that lacks a stored ID (V1) –, only archived (order
|
||||||
* "") and activated again (appended at the end of their type); the type of a variable stays, gradients are left to the
|
* "") and activated again (appended at the end of their type); the type of a variable stays, gradients are left to the
|
||||||
* builder. Values are checked per type (VariableValue); an active variable needs one. The dry run lists the posts that
|
* builder. Values are checked per type (VariableValue); an active variable needs one. The dry run lists the posts that
|
||||||
* reference a changed, archived or activated variable (ReferenceUsageQuery).
|
* reference a changed, archived or activated variable (ReferenceUsageQuery) and warns about presets that use it.
|
||||||
*/
|
*/
|
||||||
final class DiviVariablesSetAbility implements Ability, RequiresDiviFeatures
|
final class DiviVariablesSetAbility implements Ability, RequiresDiviFeatures
|
||||||
{
|
{
|
||||||
@@ -38,6 +39,13 @@ final class DiviVariablesSetAbility implements Ability, RequiresDiviFeatures
|
|||||||
private const NEW_ENTRY = ['id' => '', 'label' => '', 'value' => '', 'order' => '', 'status' => 'active',
|
private const NEW_ENTRY = ['id' => '', 'label' => '', 'value' => '', 'order' => '', 'status' => 'active',
|
||||||
'lastUpdated' => '', 'variableType' => ''];
|
'lastUpdated' => '', 'variableType' => ''];
|
||||||
|
|
||||||
|
/** At most this many names per warning. */
|
||||||
|
private const LISTED = 10;
|
||||||
|
|
||||||
|
private const IN_USE = 'Die unter affected genannten Inhalte verweisen auf geänderte oder archivierte Variablen; '
|
||||||
|
. 'archivierte Variablen bleiben dort als Verweis stehen. lit/divi-design-detach mit variable ersetzt die '
|
||||||
|
. 'Verweise vorher durch den Wert.';
|
||||||
|
|
||||||
/** @param (Closure(int): string)|null $random Random characters for new IDs (VariableBook::newId(); tests). */
|
/** @param (Closure(int): string)|null $random Random characters for new IDs (VariableBook::newId(); tests). */
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private DesignSystemWriter $writer,
|
private DesignSystemWriter $writer,
|
||||||
@@ -173,12 +181,14 @@ final class DiviVariablesSetAbility implements Ability, RequiresDiviFeatures
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$touched = array_values(array_unique($touched));
|
$touched = array_values(array_unique($touched));
|
||||||
|
$report = $touched === [] ? null : $this->usages->reportFor(new ReferenceUsageQuery($touched));
|
||||||
|
|
||||||
return new DesignPlan(
|
return new DesignPlan(
|
||||||
$book->data(),
|
$book->data(),
|
||||||
$diff,
|
$diff,
|
||||||
VariableDiff::summary($diff),
|
VariableDiff::summary($diff),
|
||||||
$touched === [] ? null : $this->usages->reportFor(new ReferenceUsageQuery($touched))
|
$report,
|
||||||
|
$this->warnings($diff, $report)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,4 +380,47 @@ final class DiviVariablesSetAbility implements Ability, RequiresDiviFeatures
|
|||||||
|
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruling V8: presets that use a changed, archived or activated variable are warnings, never a block; archiving a
|
||||||
|
* variable that posts still use is allowed (V1a) and points to lit/divi-design-detach.
|
||||||
|
*
|
||||||
|
* @param list<array<string, mixed>> $diff
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
private function warnings(array $diff, ?UsageReport $report): array
|
||||||
|
{
|
||||||
|
$presets = null;
|
||||||
|
$warnings = [];
|
||||||
|
$archives = false;
|
||||||
|
foreach ($diff as $row) {
|
||||||
|
if ($row['action'] === 'added') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$archived = $row['action'] === 'archived';
|
||||||
|
$archives = $archives || $archived;
|
||||||
|
$presets ??= PresetBook::fromDivi($this->writer->presets());
|
||||||
|
$users = array_column($presets->referencing((string) $row['id']), 'name');
|
||||||
|
if ($users !== []) {
|
||||||
|
$warnings[] = sprintf(
|
||||||
|
$archived
|
||||||
|
? 'Variable „%s“ wird archiviert, aber noch von Presets verwendet: %s.'
|
||||||
|
: 'Die Änderung an Variable „%s“ wirkt auch auf die Presets %s.',
|
||||||
|
$row['name'],
|
||||||
|
self::names($users)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($archives && $report !== null && $report->exists()) {
|
||||||
|
$warnings[] = self::IN_USE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param list<string> $names */
|
||||||
|
private static function names(array $names): string
|
||||||
|
{
|
||||||
|
return implode(', ', array_slice($names, 0, self::LISTED)) . (count($names) > self::LISTED ? ', …' : '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,4 +316,47 @@ final class DiviVariablesSetAbilityTest extends TestCase
|
|||||||
self::assertCount(2, $calls);
|
self::assertCount(2, $calls);
|
||||||
self::assertSame(VariableBook::fromDivi(VariableAreaTest::stored())->data(), $calls[1], 'the snapshot again');
|
self::assertSame(VariableBook::fromDivi(VariableAreaTest::stored())->data(), $calls[1], 'the snapshot again');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Ruling V1a/V8: archiving a used variable is allowed; presets and posts are warnings, the dry run lists posts. */
|
||||||
|
public function testArchivingAUsedVariableWarnsAndListsTheUsages(): void
|
||||||
|
{
|
||||||
|
$dry = self::assertToolError(
|
||||||
|
$this->ability(self::usages(self::used()), null, PresetBookTest::storedWithReferences())
|
||||||
|
->execute(['items' => [['id' => 'Slogan', 'status' => 'archived']]]),
|
||||||
|
'confirm_required'
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame(7, $dry['affected'][0]['post_id']);
|
||||||
|
self::assertSame([
|
||||||
|
'Variable „Slogan“ wird archiviert, aber noch von Presets verwendet: Doppelt.',
|
||||||
|
'Die unter affected genannten Inhalte verweisen auf geänderte oder archivierte Variablen; archivierte '
|
||||||
|
. 'Variablen bleiben dort als Verweis stehen. lit/divi-design-detach mit variable ersetzt die Verweise '
|
||||||
|
. 'vorher durch den Wert.',
|
||||||
|
], $dry['warnings']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testChangingAVariableWarnsAboutThePresetsThatUseIt(): void
|
||||||
|
{
|
||||||
|
$dry = self::assertToolError(
|
||||||
|
$this->ability(null, null, PresetBookTest::storedWithReferences())
|
||||||
|
->execute(['items' => [['id' => 'Eckenradius', 'value' => '12px']]]),
|
||||||
|
'confirm_required'
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame(
|
||||||
|
['Die Änderung an Variable „Eckenradius“ wirkt auch auf die Presets Lesetext.'],
|
||||||
|
$dry['warnings']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNewVariablesHaveNoWarnings(): void
|
||||||
|
{
|
||||||
|
$dry = self::assertToolError(
|
||||||
|
$this->ability(null, null, PresetBookTest::storedWithReferences())
|
||||||
|
->execute(['items' => [['type' => 'strings', 'label' => 'Gruß', 'value' => 'Hallo']]]),
|
||||||
|
'confirm_required'
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame([], $dry['warnings']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user