- Move 29 display-only event fields (subtitles, audience, tags, prices, price types, organizer) from columns into the jsonData storage; fields used for filtering, joins and calculations stay real columns - Add EventFieldsToVirtualMigration, which copies the values and drops the columns on contao:migrate - Read and write the fields in the import, the preview and the booking through EventRowCodec; other bundles' keys in the storage are kept - Validate prices in a save callback instead of the percent check that rejected every price above 100; accept a decimal comma - Do not report events as changed after a backend save: ignore the spelling of HTML entities in teaser and topics and the order of the speakers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
122 lines
4.6 KiB
PHP
122 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Mummert\ContaoWkSyncBundle\Tests\Sync;
|
|
|
|
use Mummert\ContaoWkSyncBundle\Sync\EventFields;
|
|
use Mummert\ContaoWkSyncBundle\Sync\EventRowCodec;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class EventRowCodecTest extends TestCase
|
|
{
|
|
public function testExpandReadsVirtualFieldsFromTheStorage(): void
|
|
{
|
|
$row = (new EventRowCodec())->expand([
|
|
'id' => 7,
|
|
'title' => 'Basis-Kurs',
|
|
'wkId' => '0001234',
|
|
'jsonData' => '{"wkSubTitle":"Modul 1","wkPrice1":"216.00","wkOrganizerCity":"Moritzburg","playerSize":"16:9"}',
|
|
]);
|
|
|
|
self::assertSame('Modul 1', $row['wkSubTitle']);
|
|
self::assertSame('216.00', $row['wkPrice1']);
|
|
self::assertSame('Moritzburg', $row['wkOrganizerCity']);
|
|
self::assertSame('0001234', $row['wkId']);
|
|
self::assertSame('16:9', $row['playerSize'], 'Felder anderer Erweiterungen bleiben lesbar');
|
|
self::assertArrayNotHasKey('jsonData', $row);
|
|
}
|
|
|
|
public function testExpandFillsDefaultsForMissingFields(): void
|
|
{
|
|
$codec = new EventRowCodec();
|
|
|
|
foreach ([null, '', '{}', 'kein JSON', '"text"'] as $storage) {
|
|
$row = $codec->expand(['id' => 1, 'jsonData' => $storage]);
|
|
|
|
self::assertSame('', $row['wkSubTitle']);
|
|
self::assertSame('', $row['wkOrganizerEmail']);
|
|
self::assertSame('0.00', $row['wkPrice3']);
|
|
}
|
|
|
|
self::assertSame([], array_diff(EventFields::virtual(), array_keys($codec->expand(['id' => 1]))));
|
|
}
|
|
|
|
public function testExpandKeepsAlreadyExpandedValues(): void
|
|
{
|
|
// Daten aus einem Contao-Modell sind bereits aufbereitet und haben kein JSON-Feld mehr
|
|
$row = (new EventRowCodec())->expand(['id' => 1, 'wkSubTitle' => 'Modul 2', 'wkPrice1' => '12.50']);
|
|
|
|
self::assertSame('Modul 2', $row['wkSubTitle']);
|
|
self::assertSame('12.50', $row['wkPrice1']);
|
|
}
|
|
|
|
public function testCombineMovesVirtualFieldsIntoTheStorage(): void
|
|
{
|
|
$set = (new EventRowCodec())->combine([
|
|
'title' => 'Basis-Kurs',
|
|
'wkId' => '0001234',
|
|
'wkPlacesLeft' => 12,
|
|
'wkSubTitle' => 'Modul 1 „Einführung“',
|
|
'wkPrice1' => 216.0,
|
|
'wkPrice2' => 1250.5,
|
|
'wkPriceType1' => 'Kursgebühr',
|
|
]);
|
|
|
|
self::assertSame(['title', 'wkId', 'wkPlacesLeft', 'jsonData'], array_keys($set));
|
|
self::assertSame(
|
|
['wkSubTitle' => 'Modul 1 „Einführung“', 'wkPrice1' => '216.00', 'wkPrice2' => '1250.50', 'wkPriceType1' => 'Kursgebühr'],
|
|
json_decode($set['jsonData'], true, flags: JSON_THROW_ON_ERROR),
|
|
);
|
|
self::assertStringContainsString('„Einführung“', $set['jsonData'], 'Umlaute und Anführungszeichen stehen lesbar im JSON');
|
|
}
|
|
|
|
public function testCombineKeepsStoredFieldsThatAreNotPassed(): void
|
|
{
|
|
$set = (new EventRowCodec())->combine(
|
|
['wkSubTitle' => 'Neu', 'tstamp' => 5],
|
|
'{"wkSubTitle":"Alt","wkAudience":"Lehrkräfte","playerSize":"16:9"}',
|
|
);
|
|
|
|
self::assertSame(
|
|
['wkSubTitle' => 'Neu', 'wkAudience' => 'Lehrkräfte', 'playerSize' => '16:9'],
|
|
json_decode($set['jsonData'], true, flags: JSON_THROW_ON_ERROR),
|
|
);
|
|
self::assertSame(5, $set['tstamp']);
|
|
}
|
|
|
|
public function testCombineWithoutVirtualFieldsLeavesTheStorageEmpty(): void
|
|
{
|
|
self::assertNull((new EventRowCodec())->combine(['title' => 'Ohne'])['jsonData']);
|
|
}
|
|
|
|
public function testRoundTrip(): void
|
|
{
|
|
$codec = new EventRowCodec();
|
|
$data = ['id' => 3, 'wkId' => '0009', 'wkTags' => 'a, b', 'wkPrice6' => '9.90', 'wkOrganizerEmail' => 'info@example.org'];
|
|
|
|
$row = $codec->expand($codec->combine($data));
|
|
|
|
foreach ($data as $field => $value) {
|
|
self::assertSame($value, $row[$field]);
|
|
}
|
|
}
|
|
|
|
public function testColumnsSkipVirtualFields(): void
|
|
{
|
|
self::assertSame(
|
|
['id', 'wkId', 'wkState', 'jsonData'],
|
|
(new EventRowCodec())->columns(['id', 'wkId', 'wkSubTitle', 'wkState', 'wkPrice1', 'id']),
|
|
);
|
|
}
|
|
|
|
public function testRealColumnsAreNotVirtual(): void
|
|
{
|
|
foreach (['wkId', 'wkState', 'wkInternalEventNumber', 'wkEventType', 'wkMaxPlaces', 'wkPlacesLeft', 'wkImported', 'wkCategories', 'wkCategoryPrimary', 'wkTopics', 'wkInstructor', 'wkSpeakers', 'wkNotification', 'wkConfirmationPage'] as $field) {
|
|
self::assertFalse(EventFields::isVirtual($field), $field);
|
|
}
|
|
|
|
self::assertCount(29, EventFields::virtual());
|
|
}
|
|
}
|