Schematic icon indicating copy to clipboard operation
Schematic copied to clipboard

Nepovinný parametr

Open meridius opened this issue 7 years ago • 9 comments

Ahoj,

řeším problém s nepovinným parametrem a zjištěním jeho stavu.
Mějme např. následující strukturu, kde otherData může být pole hodnot, ale může být i null nebo prázdné pole.

$data = [
	'id' => 42,
	'name' => 'Tomas Marny',
	'otherData' => [
		'data1' => 'foo',
		'data2' => 'bar',
	],
];

$data = [
	'id' => 42,
	'name' => 'Tomas Marny',
	'otherData' => [],
];

Jak v tomto případě zjistím stav "prázdnosti", resp. že otherData nemá žádné property, na které by se dalo přistupovat?
Pokud totiž entitu nadefinuji následovně, tak typ property otherData bude vždy OtherData, nehledě na vstup.

/**
 *
 * @property-read int id
 * @property-read string name
 * @property-read OtherData otherData
 */
class Data extends Entry
{
    protected static $associations = [
        'otherData' => OtherData::class,
    ];
}

/**
 *
 * @property-read string data1
 * @property-read string data2
 */
class OtherData extends Entry
{
}

meridius avatar Feb 27 '17 15:02 meridius

Teď, ať koukám jak koukám, to neuděláš. Každopádně dobrý point. Pro null by se mi líbil asi podobný zápis

/**
 * @property-read OtherData|null $otherData
 */
class Data extends Entry
{
    protected static $associations = [
        'otherData' => new NullableAssociation(OtherData::class),
    ];
}

S tím že by sis mohl nadefinovat svoje podobné požadavky (se stejným interface), aby se jako prázdné vyhodnotilo i prázdné pole (za mě výchozí null v rámci knihovny je ok).

stekycz avatar Feb 27 '17 16:02 stekycz

Pravděpodobně by se pak upravovalo vytváření nových objektů. Možná by se tak nechaly inicializovat i kolekce? Něco jako

/**
 * @property-read OtherData[] $otherData
 */
class Data extends Entry
{
    protected static $associations = [
        'otherData' => new ListAssociation(OtherData::class),
    ];
}

A případně to kombinovat (pořadí důležité, jinak by mohly být nullable prvky té kolekce)

/**
 * @property-read OtherData[]|null $otherData
 */
class Data extends Entry
{
    protected static $associations = [
        'otherData' => new NullableAssociation(new ListAssociation(OtherData::class)),
    ];
}

stekycz avatar Feb 27 '17 18:02 stekycz

Po nějakém testování pokud přijde jako hodnota null, tak to zůstane null a entita se nevytváří. Viz kód. Nicméně rozhodnutý o jiných falsey hodnotách se tam neřeší.

Zároveň do statického pole nevytvoříme novou instanci, jak uvažuji výše. Navrhl bych tedy do syntaxe názvu asociace přidat ?, pokud se má vyhodnotovat na prázdnost pomocí == namísto ===. Něco jako

/**
 * @property-read OtherData|null $otherData
 */
class Data extends Entry
{
    protected static $associations = [
        '?otherData' => OtherData::class,
    ];
}

Což trochu kopíruje syntaxy nullable hodnot v rámci PHP 7.1 :-)

stekycz avatar Feb 27 '17 22:02 stekycz

@stekycz To vypadá super! A kde to zkouším, tam to funguje. ;) @Tharos Neuvažuješ o merge?

meridius avatar Mar 01 '17 08:03 meridius

Uvažuju :), jenom chci věc doplnit i do docky. Prosím jen o malinké strpení…

Tharos avatar Mar 01 '17 08:03 Tharos

Přemýšlím ještě o dalších testech na doplnění a případné úpravy, jak to funguje.

  • Co má být výsledkem pro zápis ?orderItems[]? Má to být null nebo []? Za mě [], ale to teď asi nezafunguje. Tzn. napsat na to test.
  • Rozšířit testy na další falsey hodnoty, tzn. false, 0, 0.0, null, '' - má to vůbec smysl?
  • Jak má fungovat třeba ?author.a_? Musí být otazník u každého atributu a všechny musí být empty, aby se to aplikovalo na celého authora? Například
$book = new Book([
	'id' => 12,
	'title' => 'PHP: The Bad Parts',
	'tag_name' => 'bestseller',
	'customer_id' => 20,
	'a_firstname' => null,
	'a_surname' => null,
]);

povede na to, že $book->author === null?

stekycz avatar Mar 01 '17 09:03 stekycz

To s tím ?orderItems[] je docela good point, protože ono už teď se Schematic chová tak, že pro NULL v takovém případě vrátí NULL. Na čemž je vidět, že jsem to nikdy moc dopodrobna nerozmýšlel… :)

Hezké by asi bylo, aby se vždy vrátila instance IEntries (což by teoreticky byl BC break), a také si říkám, že definice s ? by mohla pro různé falsey hodnoty vracet IEntries obalující prázdné pole.

Co myslíš?


U embedded záznamů je trochu prekérka tohle: https://github.com/Tharos/Schematic/blob/develop/src/Schematic/Entry.php#L152 Nenapadl mě žádný jiný způsob, jak to principiálně lépe vyřešit…

Proteď bych možná šel cestou ? pro embedded záznamy uměle zakázat. Tak, jako je nyní zakázané kombinovat embedded záznamy s kolekcemi (například tag[]. skončí výjimkou).

Tharos avatar Mar 01 '17 21:03 Tharos

Jestli můžu ...

Pokud se bavíme o případu, kdy je null field zapsaný jako ?orderItems[], tak by se mělo vracet null a nic jiného. Jinak tam ? podle mě nemá smysl.
Pokud ale bude zapsaný jen jako orderItems[], tak samozřejmě vracet IEntries.

Jestli ne/rozšiřovat na další falsey hodnoty je otázka. 🤔

meridius avatar Mar 01 '17 21:03 meridius

Rozšířil jsem testy, udělal rebase a zdá se, že vše funguje tak jak bych očekával. Mrkněte na to :)

stekycz avatar Mar 02 '17 00:03 stekycz