Oznámení
Jak umožnit předat entitě místo navázaných entit jejich ‚id‘
před 5 lety
- Šaman
- Člen | 2275
Ahoj, na starším LM mi fungovala úprava ve třídě Entity, která
umožňovala předat entitě idčko místo instance entity. Takže
třeba $task->project = 3;
<?php
/**
* Umožňuje předat entitě místo navázaných entit jejich 'id'
*
* @param string $name
* @param mixed $value
*/
function __set($name, $value)
{
$property = $this->getReflection()->getEntityProperty($name);
if ($property->hasRelationship() && !($value instanceof Entity)) {
$relationship = $property->getRelationship();
$this->row->{$property->getColumn()} = $value;
$this->row->cleanReferencedRowsCache($relationship->getTargetTable(), $relationship->getColumnReferencingTargetTable());
}
else {
parent::__set($name, $value);
}
}
?>
Uvedený kód mi teď ale při persistenci vytvoří takovýhle dotaz:
UPDATE `task`
SET `project{hasOne:UDqjsm7KuS}`=3
WHERE `id` = 12
Asi to bude souviset s Mapperem, potřebuju přeložit
'project{hasOne:UDqjsm7KuS}'
na 'project_id'
. Jak na
to, pls?
před 5 lety
- Tharos
- Člen | 1042
Ahoj,
ten low-level sloupec project{hasOne:UDqjsm7KuS}
je v
Row
do té doby, dokud se ta entita nedostane k Mapperu. To proto,
protože entita do té doby netuší, v jakém sloupci ve výsledku ten cizí
klíč bude, a tak si vyrobí nějaký dočasný. Jakmile se entita dostane
k Mapperu (typicky při persistenci), hned si tyhle sloupce přemapuje podle
mapperu.
Takže u Tebe se z nějakého důvodu ta entita nedostala k Mapperu. :) Dokážeš to zreprodukovat? Nepersistuješ si tu entitu nějak úplně po svém?
před 5 lety
- Šaman
- Člen | 2275
Zvláštní – v některých případech mi to normálně funguje, třeba
data z formulářů to ukládá.
Ale nefunguje to při takovémhle jednoduchém kódu v render metodě
presenteru:
<?php
$task = $this->taskRepository->get(116); # tohle vrátí entitu podle primárního klíče. To funguje.
$task->project = 2; # v entitě jako 'project', v db jako 'project_id'
$this->taskRepository->persist($task); # hodí chybu viz níže
?>
UPDATE `task`
SET `project{hasOne:x6NOet5CTW}`=2
WHERE `id` = 116
Kódy mám na GitHubu.
Jestli je tato use-case správná, tak ti připravím sandbox s ukázkou
chyby.
P.S. Mapper jako služba samozřejmě existuje v kontejneru.
Dodatek: Tak u těch formulářů to funguje nejspíš proto, že tento sloupec neupdatuju, takže se neobjeví v dotazu. A při vytváření mi to funguje, tohle projde:
<?php
$task = new Task;
$task->note = 'bla';
$task->project = 2;
$this->taskRepository->persist($task);
?>
A na metodu persist jsem nijak nesahal, ta se bere z LM\Repository.
Editoval Šaman (4. 8. 2014 6:24)
před 5 lety
- Tharos
- Člen | 1042
Skvělý, už to vidím. Díky za odkaz na kód.
Tak to není bug a řešení je jednoduché. Nahraď v tom svém
__set
volání getReflection()
za
getCurrentReflection()
.
To, co zní možná dost WTF, je vlastně úplně jednoduché. Reflexe entity
(a hlavně jejích položek) potřebuje k ruce mapper, aby mohla určit, do
jakých sloupců se co ukládá. Metoda getReflection
proto
IMapper
přijímá jako nepovinný argument a když se jí
nepředá, neví, co se kam mapuje, a tak se právě FK ukládají do nějakých
provizorních sloupců, dokud není mapper k dispozici. Jenomže ta Tvá entita
už mapper obsahuje, a proto se jí v persist
už znovu
nepředává, a proto se už sloupce nepřemapují.
Nejpřímočařejší řešení by u Tebe bylo zavolat
$this->getReflection($this->mapper)
, což v podstatě dělá
getCurrentReflection
, která ale navíc existující reflexi
recykluje, takže zlepšuje výkon.
Editoval Tharos (4. 8. 2014 7:53)
před 5 lety
- Tharos
- Člen | 1042
Btw, krásný úkolovníček :).
před 5 lety
- Šaman
- Člen | 2275
Díky, funguje to. :)
Čekal jsem něco takového. Jen jsem myslel, že když už entita má mapper,
že si ten sloupec budu muset přeložit pomocí něho ručně.
A úkolovníček je zatím spíš takové hřiště na hraní, ale jednou
z toho chci zkusit vytvořit něco jako GTD organizér :D
Editoval Šaman (6. 8. 2014 4:22)