DiscoveredReflection: join přes dvě tabulky v select
- buff
- Člen | 63
Ahojte. Mám následující databázi:
Book (id, name, author_id)
Author (id, name, country_id)
Country (id, name)
Používám DiscoveredReflection
(musím; ve skutečnosti se ty
sloupečky nejmenují tak pěkně, to jen zde pro názornost).
Tohle funguje:
foreach ($db->table('Book') as $row) {
echo $row->ref('author_id')->ref('country_id')->name;
}
Tohle nefunguje
(No reference found for $author_id->country_id.
):
foreach ($db->table('Book')->select('author_id.country_id.name') as $row) {
echo $row->name;
}
Existuje nějaký způsob, jak druhý zápis zfunkčnit? Tedy odkázat se na
druhou cizí tabulku přímo ve volání select
? Jde mi
o použití v NiftyGridu.
Děkuji!
- buff
- Člen | 63
Ahoj. Díky za odpověď!
Tak to funguje s ConventionalReflection
, ale ne s
DiscoveredReflection
. Tedy kupodivu mi to v tomto modelovém
příkladu zafungovalo i s Discovered, ale problém je v tom, že ten sloupec
s cizím klíčem se ve skutečnosti nejmenuje country_id, ale nějak
libovolně, např fk_cntr_id. A pak už to tímto zápisem nejde.
- hrach
- Člen | 1838
ne, funguje to tak, ze napises cely nazev sloupce, nebo nejaky jeho fragment
(substring). takze pokud se sloupec bude jmenovat fk_cntr_id
, tak
toto bude fungovat:
$row->cntr->name
||select('author.cntr.name')
$row->fk_cntr->name
||select('author.fk_cntr.name')
$row->fk_cntr_id->name
||select('author.fk_cntr_id.name')
$row->k_cnt->name
– nedoporucuji, prasarna, nema logiku
- hrach
- Člen | 1838
No jasny. Jsem to napsal blbe… Pokud napises kompletni nazev sloupce, tak samozrejme to vrati hodnotu danyho klice.
$row->ref('cntr')->name || $row->cntr->name || select('author.cntr.name')
$row->ref('fk_cntr')->name || $row->fk_cntr->name || select('author.fk_cntr.name')
$row->ref('fk_cntr_id')->name || select('author.fk_cntr_id.name')
$row->ref('k_cnt')->name || $row->k_cnt->name
– nedoporucuji, prasarna, nema logiku
Editoval hrach (21. 12. 2012 0:22)
- buff
- Člen | 63
Jasně. Už je to zmatek, pardon. Napíšu znovu (pozměněnou) otázku. :-)
Mám databázi:
Book (id, name, fk_id_athr)
Author (id, name, fk_id_cntr)
Country (id, name)
fk_id_athr je cizí klíč do tabulky Author, fk_id_cntr je cizí klíč do tabulky Country.
A mám následující kód:
<?php
$table = $this->context->database->table('book');
foreach($table as $row) {
echo $row->ref('fk_id_athr')->ref('fk_id_cntr')->name; //vypíše název země
echo $row->id_athr->id_cntr->name; //vypíše název země
}
$table = $this->context->database->table('book')
->select('id_athr.id_cntr.name');
foreach($table as $row) {
echo $row->name; //PDO exception: No reference found for $id_athr->id_cntr.
}
?>
Čili „šipková“ notace už mi funguje perfektně, „tečková“ notace ve volání metody select však ne. Co dělám špatně?
- buff
- Člen | 63
Toto ->select('id_athr.id_cntr.name');
je přesně to, co
jsem tam měl původně.
A toto ->select('athr.cntr.name');
bohužel padá
s analogickou
hláškou No reference found for $athr->cntr.
Takže je tam bug?
Ty názvy sloupců jsem vymyslel já, abych vám aspoň zlehounka nastínil, jaká je situace v té reálné databázi ;-)
- vvoody
- Člen | 910
Myslím že som našiel bug v SqlBuilder->buildJoins().
Testoval som na kode:
$table = $c->table('book')->select('book.*, athr.name AS aname, athr.cntr.name AS cname');
foreach ($table as $row) {
dump($row);
}
a dátach:
DROP TABLE IF EXISTS `author`;
CREATE TABLE `author` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`fk_id_cntr` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_id_cntr` (`fk_id_cntr`),
CONSTRAINT `author_ibfk_1` FOREIGN KEY (`fk_id_cntr`) REFERENCES `country` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO `author` (`id`, `name`, `fk_id_cntr`) VALUES
(1, 'Pišta', 1);
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`fk_id_athr` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_id_athr` (`fk_id_athr`),
CONSTRAINT `book_ibfk_1` FOREIGN KEY (`fk_id_athr`) REFERENCES `author` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO `book` (`id`, `name`, `fk_id_athr`) VALUES
(1, 'Islo vajce na vandrovku', 1);
DROP TABLE IF EXISTS `country`;
CREATE TABLE `country` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO `country` (`id`, `name`) VALUES
(1, 'Slovensko');
Problém bol celkom jasný: No reference found for $athr->cntr
Prečo metóda $reflection->getBelongsToReference($parent, $name) dostala ako
parameter $paren = ‚athr‘ namiesto správneho ‚author‘. Tieto úpravy mi
to fixli, ale netrufam si povedať či to niečo ine nerozoserie.
protected function buildJoins($val, $inner = FALSE)
{
$reflection = $this->selection->getConnection()->getDatabaseReflection();
$joins = array();
preg_match_all('~\\b([a-z][\\w.:]*[.:])([a-z]\\w*|\*)(\\s+IS\\b|\\s*<=>)?~i', $val, $matches);
foreach ($matches[1] as $names) {
// v prvej iteracii bude parent a alias v ON podmienke totozny
$alias = $parent = $this->selection->getName();
if ($names !== "$parent.") { // case-sensitive
preg_match_all('~\\b([a-z][\\w]*|\*)([.:])~i', $names, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
list(, $name, $delimiter) = $match;
if ($delimiter === ':') {
list($table, $primary) = $reflection->getHasManyReference($parent, $name);
$column = $reflection->getPrimary($parent);
} else {
list($table, $column) = $reflection->getBelongsToReference($parent, $name);
$primary = $reflection->getPrimary($table);
}
$joins[$name] = ' '
. (!isset($joins[$name]) && $inner && !isset($match[3]) ? 'INNER' : 'LEFT')
. ' JOIN ' . $this->driver->delimite($table) . ($table !== $name ? ' AS ' . $this->driver->delimite($name) : '')
// before:
// . ' ON ' . $this->driver->delimite($parent) . '.' . $this->driver->delimite($column)
// after
. ' ON ' . $this->driver->delimite($alias) . '.' . $this->driver->delimite($column)
. ' = ' . $this->driver->delimite($name) . '.' . $this->driver->delimite($primary);
// treba rozlisovat realny nazov tabulky potreby pre reflection od aliasu v ON podmienke
$alias = $name;
$parent = $table;
}
}
}
return $joins;
}
- hrach
- Člen | 1838
jasny, to je ten bug, kterej sem uz fixnul tady: https://github.com/…5731414c9dc0
budu se na to muset znovu podivat a trochu do dopracovat :) (to rfc, ktery bude obsahovat i toto…)
- hrach
- Člen | 1838
Zjistil jsem, ze jsem to uz u sebe asi opravoval driv,
takze to mam dokonce mimo ten velkej refactoring: tady je ten dulezity
commit:
https://github.com/…f6f167dd5c22
edit: https://github.com/…tte/pull/912
Editoval hrach (22. 12. 2012 14:35)