Files

151 lines
7.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Compose;
use InvalidArgumentException;
use LIT\MCP\Integrations\Divi\Compose\DynamicContentRules;
use LIT\MCP\Integrations\Divi\Compose\LoopScope;
use LIT\MCP\Tests\Support\DiviFixtures;
use PHPUnit\Framework\TestCase;
/** Rulings X2/X5 and the security boundary "Typabgleich": loop_* names only in a loop of their kind. */
final class DynamicContentRulesTest extends TestCase
{
/** The map of a composition inside a loop: forPost() plus loopFields() of every kind (worst case). */
private const MAP = [
'post_title' => ['before' => 'richtext', 'after' => 'richtext'],
'loop_post_title' => ['before' => 'richtext', 'after' => 'richtext', 'loop_position' => 'text'],
'loop_post_meta_key_manual_custom_field' => ['select_loop_meta_key' => 'select', 'loop_meta_key' => 'text'],
'loop_term_name' => ['before' => 'richtext', 'after' => 'richtext', 'loop_position' => 'text'],
'loop_term_meta_key_manual_custom_field' => ['select_loop_meta_key' => 'select', 'loop_meta_key' => 'text'],
'loop_user_meta_key_manual_custom_field' => ['select_loop_meta_key' => 'select', 'loop_meta_key' => 'text'],
'loop_menu_text' => ['before' => 'richtext', 'after' => 'richtext', 'loop_position' => 'text'],
'loop_acf_team|||name' => ['before' => 'richtext', 'after' => 'richtext'],
];
private static function rules(?LoopScope $loop = null): DynamicContentRules
{
return new DynamicContentRules(DiviFixtures::designSystem(), self::MAP, $loop);
}
private static function assertRefused(DynamicContentRules $rules, string $name, string $message): void
{
try {
$rules->fieldsFor($name);
self::fail('Accepted: ' . $name);
} catch (InvalidArgumentException $e) {
self::assertSame($message, $e->getMessage(), $name);
}
}
/** Spec §9 / X5: without a loop every loop_* name is refused – also one the map names. */
public function testWithoutALoopEveryLoopOptionIsRefused(): void
{
foreach ([self::rules(), self::rules(LoopScope::none())] as $rules) {
foreach (array_keys(self::MAP) as $name) {
if (! str_starts_with($name, 'loop_')) {
continue;
}
self::assertRefused(
$rules,
$name,
sprintf(
'Schleifen-Inhalt "%s" braucht eine Divi-Schleife in diesem Modul oder einem übergeordneten '
. 'Element (Abschnitt, Zeile, Spalte, Gruppe).',
$name
)
);
}
}
}
public function testALoopOptionOfTheLoopsKindHasItsMapSettings(): void
{
self::assertSame(self::MAP['loop_post_title'], self::rules(LoopScope::ofQueryType('post_types'))
->fieldsFor('loop_post_title'));
self::assertSame(self::MAP['loop_post_title'], self::rules(LoopScope::ofQueryType('current_page'))
->fieldsFor('loop_post_title'));
self::assertSame(self::MAP['loop_term_name'], self::rules(LoopScope::ofQueryType('post_taxonomies'))
->fieldsFor('loop_term_name'));
self::assertSame(
self::MAP['loop_user_meta_key_manual_custom_field'],
self::rules(LoopScope::ofQueryType('user_roles'))->fieldsFor('loop_user_meta_key_manual_custom_field')
);
self::assertSame(self::MAP['loop_menu_text'], self::rules(LoopScope::ofQueryType('menus'))
->fieldsFor('loop_menu_text'));
}
/**
* Security boundary: Divi reads the meta of the loop object's ID whatever the object is – post meta
* of the post with the term's ID (DynamicContentLoopOptions.php:145-158). A hard error, not a hint.
*
* @return array<string, array{string, string, string}>
*/
public static function mismatches(): array
{
return [
'post meta in a term loop' => ['post_taxonomies', 'loop_post_meta_key_manual_custom_field', 'Terme'],
'post meta in a user loop' => ['user_roles', 'loop_post_meta_key_manual_custom_field', 'Benutzer'],
'post meta in a menu loop' => ['menus', 'loop_post_meta_key_manual_custom_field', 'Menü'],
'user meta in a post loop' => ['post_types', 'loop_user_meta_key_manual_custom_field', 'Beiträge'],
'term meta in a post loop' => ['current_page', 'loop_term_meta_key_manual_custom_field', 'Beiträge'],
'term meta in a user loop' => ['user_roles', 'loop_term_meta_key_manual_custom_field', 'Benutzer'],
'term name in a post loop' => ['post_types', 'loop_term_name', 'Beiträge'],
'post title in a menu loop' => ['menus', 'loop_post_title', 'Menü'],
'menu text in a term loop' => ['post_taxonomies', 'loop_menu_text', 'Terme'],
'acf row in a post loop' => ['post_types', 'loop_acf_team|||name', 'Beiträge'],
'post title in an acf repeater loop' => ['repeater_team', 'loop_post_title', 'repeater_team'],
'acf row in an acf repeater loop' => ['repeater_team', 'loop_acf_team|||name', 'repeater_team'],
];
}
/** @dataProvider mismatches */
public function testAnOptionOfAnotherKindIsRefused(string $queryType, string $name, string $label): void
{
self::assertRefused(
self::rules(LoopScope::ofQueryType($queryType)),
$name,
sprintf('Schleifen-Inhalt "%s" passt nicht zur Schleife dieses Elements (Typ: %s).', $name, $label)
);
}
public function testALoopOptionTheMapDoesNotNameIsUnknown(): void
{
$rules = self::rules(LoopScope::ofQueryType('post_types'));
foreach (['loop_post_date', 'loop_post_meta_key_telefon', 'loop_'] as $name) {
try {
$rules->fieldsFor($name);
self::fail('Accepted: ' . $name);
} catch (InvalidArgumentException $e) {
self::assertStringContainsString('Unbekannter Name "' . $name . '"', $e->getMessage());
}
}
// The default map (registry unavailable) names no loop option.
$this->expectExceptionMessage('Unbekannter Name "loop_post_title"');
(new DynamicContentRules(DiviFixtures::designSystem(), null, LoopScope::ofQueryType('post_types')))
->fieldsFor('loop_post_title');
}
public function testOtherNamesAreTheSameInsideALoop(): void
{
foreach ([null, LoopScope::ofQueryType('post_taxonomies')] as $loop) {
$rules = self::rules($loop);
self::assertSame(self::MAP['post_title'], $rules->fieldsFor('post_title'));
self::assertSame(DynamicContentRules::META_SETTINGS, $rules->fieldsFor('custom_meta_telefon'));
self::assertSame(DynamicContentRules::DESIGN_SETTINGS, $rules->fieldsFor('gvid-s1'));
foreach (['custom_meta__edit_lock', 'site_title'] as $name) {
try {
$rules->fieldsFor($name);
self::fail('Accepted: ' . $name);
} catch (InvalidArgumentException $e) {
self::assertStringContainsString('Unbekannter Name "' . $name . '"', $e->getMessage());
}
}
}
}
}