tiny ‘n’ smart
database layer

Odkazy: dibi | API reference

Oznámení

Omlouváme se, provoz fóra byl ukončen

Jak umožnit předat entitě místo navázaných entit jejich ‚id‘

před 4 lety

Šaman
Člen | 2253
+
0
-

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 4 lety

Tharos
Člen | 1039
+
0
-

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 4 lety

Šaman
Člen | 2253
+
0
-

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 4 lety

Tharos
Člen | 1039
+
0
-

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 4 lety

Tharos
Člen | 1039
+
0
-

Btw, krásný úkolovníček :).

před 4 lety

Šaman
Člen | 2253
+
0
-

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)