vrana/notorm

Nefunkční reference

Opened this issue · 6 comments

Mám objekt Product, který v sobě uchovává adekvátní NotORM_Row (dejme tomu $this->databaseRow, DatabaseRow je poděděná třída). Později chci udělat toto:

$this->databaseRow->product_element()

...jenže to vyhodí prázdný result, ačkoliv v databázi nějaké takové elementy jsou. Když dumpnu objekt, vypadá to nějak takto:

NotORM_MultiResult(35) {
   "result" private => NotORM_Result(32) {
      "single" protected => TRUE
      "select" protected => array(0) 
      "conditions" protected => array(1) [
         0 => "id" (2)
      ]
      "where" protected => array(1) [
         0 => "id = '156378'" (13)
      ]
      "parameters" protected => array(0) 
      "order" protected => array(0) 
      "limit" protected => NULL
      "offset" protected => NULL
      "group" protected => ""
      "having" protected => ""
      "union" protected => array(0) 
      "unionOrder" protected => array(0) 
      "unionLimit" protected => NULL
      "unionOffset" protected => NULL
      "data" protected => array(1) {
         156378 => Javorek\Model\DatabaseRow(15) { ... }
      }
      "referencing" protected => array(1) {
         "SELECT * FROM product_element WHERE (product_element.product_id IN (156378))" => array(1) { ... }
      }
      "aggregation" protected => array(0) 
      "accessed" protected => NULL
      "access" protected => array(1) {
         "id" => TRUE
      }
      "keys" protected => array(0) 
      "connection" protected => NULL
      "driver" protected => NULL
      "structure" protected => NULL
      "cache" protected => NULL
      "notORM" protected => NotORM(12) {
         "connection" protected => Javorek\Model\DatabaseConnection(1) { ... }
         "driver" protected => "mysql" (5)
         "structure" protected => NotORM_Structure_Convention(3) { ... }
         "cache" protected => NULL
         "notORM" protected => NULL
         "table" protected => NULL
         "primary" protected => NULL
         "rows" protected => NULL
         "referenced" protected => array(0) 
         "debug" protected => array(2) [ ... ]
         "freeze" protected => TRUE
         "rowClass" protected => "Javorek\Model\DatabaseRow" (25)
      }
      "table" protected => "product" (7)
      "primary" protected => "id" (2)
      "rows" protected => array(1) {
         156378 => Javorek\Model\DatabaseRow(15) { ... }
      }
      "referenced" protected => array(1) {
         "project" => NotORM_Result(32) { ... }
      }
      "debug" protected => FALSE
      "freeze" protected => FALSE
      "rowClass" protected => "NotORM_Row" (10)
   }
   "column" private => "product_id" (10)
   "active" private => "156378" (6)
   "single" protected => FALSE
   "select" protected => array(0) 
   "conditions" protected => array(1) [
      0 => "product_element.product_id" (26)
   ]
   "where" protected => array(1) [
      0 => "product_element.product_id IN (156378)" (38)
   ]
   "parameters" protected => array(0) 
   "order" protected => array(0) 
   "limit" protected => NULL
   "offset" protected => NULL
   "group" protected => ""
   "having" protected => ""
   "union" protected => array(0) 
   "unionOrder" protected => array(0) 
   "unionLimit" protected => NULL
   "unionOffset" protected => NULL
   "data" protected => NULL
   "referencing" protected => array(0) 
   "aggregation" protected => array(0) 
   "accessed" protected => NULL
   "access" protected => NULL
   "keys" protected => array(0) 
   "connection" protected => NULL
   "driver" protected => NULL
   "structure" protected => NULL
   "cache" protected => NULL
   "notORM" protected => NotORM(12) {
      "connection" protected => Javorek\Model\DatabaseConnection(1) {
         "convertIdentifiers" private => TRUE
      }
      "driver" protected => "mysql" (5)
      "structure" protected => NotORM_Structure_Convention(3) {
         "primary" protected => "id" (2)
         "foreign" protected => "%s_id" (5)
         "table" protected => "%s" (2)
      }
      "cache" protected => NULL
      "notORM" protected => NULL
      "table" protected => NULL
      "primary" protected => NULL
      "rows" protected => NULL
      "referenced" protected => array(0) 
      "debug" protected => array(2) [
         0 => "Javorek\Model\DatabaseModel" (27)
         1 => "debug" (5)
      ]
      "freeze" protected => TRUE
      "rowClass" protected => "Javorek\Model\DatabaseRow" (25)
   }
   "table" protected => "product_element" (15)
   "primary" protected => "id" (2)
   "rows" protected => NULL
   "referenced" protected => array(0) 
   "debug" protected => FALSE
   "freeze" protected => FALSE
   "rowClass" protected => "NotORM_Row" (10)
}

Vidím tam SQL dotaz, tedy

SELECT * FROM product_element WHERE (product_element.product_id IN (156378))

...ten jsem zkoušel normálně přes Adminer a vyhodí správný set výsledků. Nechápu co se děje, ale stálo mě to dnes hrozně moc vlasů :( Nějak víc do hloubky to ladit nemůžu (čas), ale pokud by bylo třeba ještě něco poskytnout, můžu se pokusit.

EDIT1: Jinak když dumpnu ten samotný $this->databaseRow, vypadá takto:

Javorek\Model\DatabaseRow(15) {
   "modified" private => array(0) 
   "row" protected => array(4) {
      "id" => "156378" (6)
      "project_id" => "13" (2)
      "variant_of" => NULL
      "hidden" => "0"
   }
   "result" protected => NotORM_Result(32) {
      "single" protected => TRUE
      "select" protected => array(0) 
      "conditions" protected => array(1) [
         0 => "id" (2)
      ]
      "where" protected => array(1) [
         0 => "id = '156378'" (13)
      ]
      "parameters" protected => array(0) 
      "order" protected => array(0) 
      "limit" protected => NULL
      "offset" protected => NULL
      "group" protected => ""
      "having" protected => ""
      "union" protected => array(0) 
      "unionOrder" protected => array(0) 
      "unionLimit" protected => NULL
      "unionOffset" protected => NULL
      "data" protected => array(1) {
         156378 => Javorek\Model\DatabaseRow(15) { *RECURSION* }
      }
      "referencing" protected => array(1) {
         "SELECT * FROM product_element WHERE (product_element.product_id IN (156378))" => array(1) { ... }
      }
      "aggregation" protected => array(0) 
      "accessed" protected => NULL
      "access" protected => array(1) {
         "id" => TRUE
      }
      "keys" protected => array(0) 
      "connection" protected => NULL
      "driver" protected => NULL
      "structure" protected => NULL
      "cache" protected => NULL
      "notORM" protected => NotORM(12) {
         "connection" protected => Javorek\Model\DatabaseConnection(1) { ... }
         "driver" protected => "mysql" (5)
         "structure" protected => NotORM_Structure_Convention(3) { ... }
         "cache" protected => NULL
         "notORM" protected => NULL
         "table" protected => NULL
         "primary" protected => NULL
         "rows" protected => NULL
         "referenced" protected => array(0) 
         "debug" protected => array(2) [ ... ]
         "freeze" protected => TRUE
         "rowClass" protected => "Javorek\Model\DatabaseRow" (25)
      }
      "table" protected => "product" (7)
      "primary" protected => "id" (2)
      "rows" protected => array(1) {
         156378 => Javorek\Model\DatabaseRow(15) { *RECURSION* }
      }
      "referenced" protected => array(1) {
         "project" => NotORM_Result(32) { ... }
      }
      "debug" protected => FALSE
      "freeze" protected => FALSE
      "rowClass" protected => "NotORM_Row" (10)
   }
   "connection" protected => NULL
   "driver" protected => NULL
   "structure" protected => NULL
   "cache" protected => NULL
   "notORM" protected => NULL
   "table" protected => NULL
   "primary" protected => NULL
   "rows" protected => NULL
   "referenced" protected => array(0) 
   "debug" protected => FALSE
   "freeze" protected => FALSE
   "rowClass" protected => "NotORM_Row" (10)
}

EDIT2: Nový poznatek je, že pokud si to nechám vypsat v šabloně poprvé, vyhodí mi to správný počet elementů. Pokud to udělám podruhé hned o řádek níže, vyhodí 0. Takže opět nějaká zákeřná cache? :(

Vyzkoušej to s aktuální verzí z Gitu, převeď příklad na demo databázi NotORM a zkus to bez poděděného objektu. Pokud to bez podědění bude fungovat, tak zkus prázdného potomka a postupně do něj přidávat to, co máš v DatabaseRow.

Takhle se nám chybu snad podaří najít chybu ke vzájemné spokojenosti.

Napiš sem (do nového komentáře) co nejstručnější příklad, pomocí kterého se dá chyba reprodukovat.

Neměl jsem čas se tomu moc věnovat, nějak jsem to obešel a pokračoval ve vývoji. Aplikace už je ale za mnou, takže bych si mohl najít čas to odladit a poskytnout nějaké další info, ale nevím kdy se k tomu dostanu. Každopádně aktuální verze z Gitu to byla, protože mám NotORM jako git submodule a aktualizuji ho.

Projekt, na kterém jsem toto chování sledoval (na jiném jsem NotORM ještě nestačil použít, teď dělám něco v Djangu), po mě převzal @kacer, takže další postup bude na něm.

V podstatě vždy se to projevilo, pokud existoval např. objekt Product a ten v sobě uchovával nějaký DatabaseRow. Přistoupilo-li se k tomu databázovému řádku poprvé, bylo vše OK a reference fungovaly. Pokud kdykoliv později, vracelo to prázdné výsledky. Šlo nakonec obejít tak, že v konstruktoru objekt Product natáhl z databáze vždy vše co potřeboval (svá data i všechna related data, naštěstí šlo jen o dva malé dotazy) a pak pracoval pokaždé už jen s těmito výsledky.

Nedávno jsem ale tuto třídu refactoroval a nejlepší řešení s nejméně frustracemi bylo nakonec nepředávat Productu žádný DatabaseRow, ale rovnou objekt NotORM, aby si mohl ta data vytahovat sám. Předání DatabaseRow jako parametr tento objekt řádku totiž zjevně nějak záhadně připravovalo o schopnost dále pracovat s related daty.

Jak jsem psal, potřeboval bych krátký reprodukovatelný příklad.

Po třech letech jsem na to opět narazil a začal jsem se v tom hrabat. Příklad je na gistu zde: https://gist.github.com/kacer/7931757. Vyzkoušeno s aktuálním verzí staženou z notorm.com.

Druhý foreach zničehonic nefunguje.

Zjistil jsem, že když v https://github.com/vrana/notorm/blob/master/NotORM/MultiResult.php#L134 odstraním referenci, takže tam bude prosté přiřazení:

$this->data = $referencing[$this->active];

Tak to najednou začne fungovat.

Nechával jsem si v execute() vypisovat $this->result->referencing a zjistil, že při prvním foreachi "něco" nastavuje položky v $this->result->referencing[$this->__toString()] na NULL. Co to je, jsem nezjistil.