Problém při spojování tabulek v Nette\Database\Table\Selection
- theo
- Člen | 57
Narazil jsem na docela podivný problém. Mám tabulky
CREATE TABLE languages (
id integer NOT NULL auto_increment,
name varchar(255) NOT NULL,
...
PRIMARY KEY (id)
);
CREATE TABLE serials (
id integer NOT NULL auto_increment,
language_id integer NOT NULL,
...
PRIMARY KEY (id),
CONSTRAINT FOREIGN KEY (language_id) REFERENCES languages(id)
);
Používám DiscoveredReflection, který podle všeho správně analyzoval
vazby a klíče. Usuzuji tak z toho, že něco jako
dump(DiscoveredReflection->structure)
vypadá takto:
array(3) {
primary => array(2) {
serials => "id" (2)
languages => "id" (2)
}
hasMany => array(1) {
languages => array(1) {
serials => "language_id" (11)
}
}
belongsTo => array(1) {
serials => array(4) {
language_id => "languages" (9)
}
}
}
A teď chci udělat v modelu Serials něco jako
<?php
class Serials extends Nette\Database\Table\Selection {
...
public function view() {
return $this->select('serials.*, languages.name AS language_name');
}
...
}
?>
Jako výsledek očekávám něco jako:
id | name | language_id | language_name | ...
---+----------+-------------+---------------+----
1 | Serial 1 | cs | čeština | ...
2 | Serial 2 | sk | slovenčina | ...
...
Problém je v tom, že místo očekávaného seznamu hodnot se to zacyklí na vykonávání dotazu
SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = 'serials'
načež to spadne po uplynutí maximálního času pro běh skriptu. Pokud
odstraním languages.name AS language_name
z dotazu, vše
proběhne bez problémů (ale pochopitelně bez potřebného sloupce).
Můžete mi prosím někdo přiblížit v čem by mohl být zakopaný pes?
(Nette Framework 2.0.1 (revision 94abcaa released on 2012–02–29), PHP 5.3.10, MySQL 5.1.61)
- theo
- Člen | 57
Děkují za promptní (ne)odpověď na stupidně jednoduchou otázku…
Problémem je to, že moje tabulky se jmenují v množném čísle
(serials
, languages
) a
DiscoveredReflection
bůhví proč hledá název tabulky pomocí
srovnávání názvu tabulky s názvem odkazujícího sloupce namísto toho,
aby poměrně logicky hledala v názvu odkazující tabulky (viz. zde: https://api.nette.org/…ion.php.html#130)…
No nic…
Řešením pro mě v tomto případě bylo vytvoření vlastní databázové
reflexe, která je potomkem DiscoveredReflection
a která před
tím, než předá rodiči ke zpracování název klíče jej převede do
jednotného čísla (lidově řečeno uřeže ‚s‘, ‚es‘, ‚ies‘,
případně další řetězce z konce názvu tabulky, naštěstí si to už
stripos()
uvnitř rodičovské metody přežvýká). Podle mého je
to sice na hranici hacku, nicméně na nic lepšího jsem prostě nepřišel.
Moje databázová reflexe vypadá přibližně takto:
<?php
class MyReflection extends DiscoveredReflection {
...
public function getBelongsToReference($table, $key) {
$key = $this->singelize($key);
return parent::getBelongsToReference($table, $key);
}
public function getHasManyReference($table, $key) {
$key = $this->singelize($key);
return parent::getHasManyReference($table, $key);
}
protected function singelize($key) {
return preg_replace('/^(.*?)(s|es|ies)$/i', '$1', $key);
}
}
?>