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)