Invalid argument supplied for foreach() při procházení tabulkou přes related
- TomasHalasz
- Bronze Partner | 79
Ahoj, mám následující problém.
Mám tři tabulky:
cl_types
cl_types_parameters
cl_parameters
cl_types_parameters je s cl_parameters svázáné přes foreign keys
ALTER TABLE `cl_types_parameters`
ADD CONSTRAINT `cl_types_parameters_ibfk_2` FOREIGN KEY (`cl_parameters_id`) REFERENCES `cl_parameters` (`id`);
Následující kód mi funguje:
{foreach $ClTypes_radek->related('cl_types_parameters')->order('par_num') as $radek2}
{$radek2->cl_parameters->label_parameter}
{/foreach}
Bez chyby pro každý řádek z cl_types vypisuje pro odpovídající cl_types_parameters hodnotu label_parameter z cl_parameters .
No a pak mám tyto tabulky:
offers_items
offers_items_parameters
a stejnou cl_parameters jako výše
Mám tam vazbu:
ALTER TABLE `offers_items_parameters`
ADD CONSTRAINT `offers_items_parameters_ibfk_2` FOREIGN KEY (`cl_parameters_id`) REFERENCES `cl_parameters` (`id`);
A chci vypisovat pro každý řádek offers_items jeho záznamy offers_items_parameters a k nim z cl_parameters->label_parameter. Dělám to takto:
{foreach $OffersItems as $Items_radek}
{foreach $Items_radek->related('offers_items_parameters') as $Parameters_radek2}
<td>{$Parameters_radek2->cl_parameters->label_parameter}</td>
{/foreach}
{/foreach}
a dostávám chybu: Invalid argument supplied for
foreach()
na řádku:
<td>{$Parameters_radek2->cl_parameters->label_parameter}</td>
Když to zkusím takto tak to jde:
{foreach $Items_radek->related('offers_items_parameters') as $Parameters_radek2}
{foreach $Parameters_radek2->related('cl_parameters','id') as $Parameters_radek3}
<td>{$Parameters_radek3->label_parameter}</td>
<td>{$Parameters_radek2->value_parameter}</td>
<td>{$Parameters_radek3->units}</td>
{/foreach}
{/foreach}
Takže mi z nějakého důvodu nefunguje automatická vazba z tabulky
offers_items_parameters přes foreign key na tabulku
cl_parameters, která z tabulky cl_types_parameters
funguje.
Sedím nad tím už pár hodin a pořád netuším kde je chyba :-(
Zkoušeno na Nette Framework 2.0.3 (revision eb558ae released on
2012–04–04)
i na Nette Framework 2.1-dev se stejným výsledkem.
díky za každou radu
Editoval TomasHalasz (23. 6. 2012 12:33)
- TomasHalasz
- Bronze Partner | 79
Ne, $Parameters_radek2->related(‚cl_parameters‘,‚id‘) vrací jen jeden řádek. V tabulce cl_parameters je id primární klíč a tedy pro každé id je tam jen jeden záznam.
Chápu, že $Parameters_radek2->related(‚cl_parameters‘,‚id‘) může vrátit více záznamů, ale tím jsem jen obešel to že mi nefungovalo toto: $Parameters_radek2->cl_parameters->label_parameter}
- vvoody
- Člen | 910
TomasHalasz napsal(a):
Ne, $Parameters_radek2->related(‚cl_parameters‘,‚id‘) vrací jen jeden řádek. V tabulce cl_parameters je id primární klíč a tedy pro každé id je tam jen jeden záznam.
Na to je funkcia ref, nie related, nepliest si ich:
- vracia activerow (riadok)
- druhy parameter je FK ktory je sucastou riadku nad ktorym ref volas
- vracia selection (mnozinu riadkov)
- druhy parameter je FK ktory je vo vezobnej tabulke
Co mozeme robit so selection?
- Preiterovat vo foreach a ziskat jednotlive activerow.
- atd
Co mozeme robit s activerow?
- volat nad nim related a tym ziskat selection z inej tabulky (referencing rows)
- volat nad nim ref a tym ziskat activerow z inej tabulky (referenced row)
- referenced row mozno ziskat pri dodrzani urcitych konvencii aj priamo z property activerow jej nazov je nazov tabulky kde sa odkazovany riadok nachadza (samozrejme ze to property nieje ale vdaka magickym metodam to tak vyzera) ak nemas rad magiu tak proste pouzivaj funkciu ref
- atd
Edit: teraz som si vsimol ze ako druhy parameter related davas PK, logicky je ale pre tu funkciu taka informacia uplne k nicomu, ona potrebuje vediet co je FK. PK jednotlivych tabuliek si vie zistit sama kedze PK je jeden, FK moze byt viacero.
Editoval vvoody (23. 6. 2012 13:02)
- vvoody
- Člen | 910
Ja ze si pisem s TomasHalasz :D hej presne tak. Netusim ktoru funkciu musi pouzit lebo z prveho prispevku som nevylustil typ vazby medzi inkriminovanymi tabulkami. Ale aj keby som to zistil radsej sa pokusam vysvetlit ktoru funkciu kedy zvolit aby chybu neopakoval. Tiez som mal s tym spociatku strasny problem :).
- TomasHalasz
- Bronze Partner | 79
Už jsem tu :-) Díky za rady, hned se na to podívám.
Jen to shrnu:
Jde mi o to, že $riadokVTabulke1->tabulka2 mi v prvním
případě funguje a v druhém $riadokVTabulke3->tabulka2
nefunguje. Pojmenování id primary key a foreign key podle NOTORM dodrženo
mám. Když to zjednoduším tak toto funguje:
radek_z_tabulky_cl_types_parameters->cl_parameters->label_parameter
Toto nefunguje:
radek_z_tabulky_offers_items_parameters->cl_parameters->label_parameter
Tady jsou dumpy:
--
-- Databáze: `kalkulator`
--
-- --------------------------------------------------------
--
-- Struktura tabulky `cl_parameters`
--
CREATE TABLE IF NOT EXISTS `cl_parameters` (
`company_id` int(11) NOT NULL COMMENT 'číslo firmy',
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'číslo parametru',
`label_parameter` text NOT NULL COMMENT 'označení parametru',
`units` varchar(10) NOT NULL COMMENT 'jednotky',
`par_num` int(11) NOT NULL COMMENT 'pořadí parametru v cl_types_parameters',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='číselník parametrů' AUTO_INCREMENT=6 ;
--
-- Vypisuji data pro tabulku `cl_parameters`
--
INSERT INTO `cl_parameters` (`company_id`, `id`, `label_parameter`, `units`, `par_num`) VALUES
(1, 1, 'šířka', 'mm', 1),
(1, 2, 'výška', 'mm', 2),
(1, 3, 'barva', '', 3),
(1, 4, 'barva 2', '', 4),
(1, 5, 'barva 3', '', 5);
-- --------------------------------------------------------
--
-- Struktura tabulky `cl_types`
--
CREATE TABLE IF NOT EXISTS `cl_types` (
`id_firm` int(11) NOT NULL COMMENT 'číslo firmy',
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'číslo typu',
`label_type` text NOT NULL COMMENT 'označení typu',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='číselník typů' AUTO_INCREMENT=16 ;
--
-- Vypisuji data pro tabulku `cl_types`
--
INSERT INTO `cl_types` (`id_firm`, `id`, `label_type`) VALUES
(1, 1, 'Typ 1'),
(1, 2, 'Typ 2'),
(1, 3, 'Typ 3'),
(1, 4, 'Typ 4'),
(1, 5, 'Typ 5'),
(1, 6, 'Typ 6'),
(1, 7, 'Typ 7'),
(1, 8, 'Typ 8'),
(1, 9, 'Typ 9'),
(1, 10, 'Typ 10'),
(1, 11, 'Typ 11'),
(1, 12, 'Typ 12'),
(1, 13, 'Typ 13'),
(1, 14, 'Typ 14'),
(1, 15, 'Typ 15');
-- --------------------------------------------------------
--
-- Struktura tabulky `cl_types_parameters`
--
CREATE TABLE IF NOT EXISTS `cl_types_parameters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_firm` int(11) NOT NULL COMMENT 'číslo firmy',
`cl_types_id` int(11) NOT NULL COMMENT 'číslo typu',
`cl_parameters_id` int(11) NOT NULL COMMENT 'číslo parametru',
`min_value` float NOT NULL COMMENT 'minimální hodnota',
`max_value` float NOT NULL COMMENT 'maximální hodnota',
`par_num` int(11) NOT NULL COMMENT 'pořadí v par_num v ceníku',
PRIMARY KEY (`id`),
KEY `cl_parameters_id` (`cl_parameters_id`),
KEY `cl_types_id` (`cl_types_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='přiřazení parametrů k typům' AUTO_INCREMENT=30 ;
--
-- Vypisuji data pro tabulku `cl_types_parameters`
--
INSERT INTO `cl_types_parameters` (`id`, `id_firm`, `cl_types_id`, `cl_parameters_id`, `min_value`, `max_value`, `par_num`) VALUES
(3, 1, 1, 2, 105, 205, 1),
(4, 1, 1, 1, 305, 405, 2),
(7, 1, 2, 2, 555, 555, 1),
(13, 1, 1, 3, 0, 0, 3),
(25, 1, 2, 1, 300, 300, 2),
(27, 1, 3, 2, 500, 1500, 1),
(28, 1, 3, 1, 500, 1500, 2),
(29, 1, 1, 4, 0, 0, 4);
-- --------------------------------------------------------
--
-- Struktura tabulky `offers_items`
--
CREATE TABLE IF NOT EXISTS `offers_items` (
`id_firm` int(11) NOT NULL COMMENT 'číslo firmy',
`offers_main_id` int(11) NOT NULL COMMENT 'číslo nabídky',
`offers_groups_id` int(11) NOT NULL COMMENT 'číslo skupiny',
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'číslo položky',
`label_item` text NOT NULL COMMENT 'popis položky',
`cl_types_id` int(11) NOT NULL COMMENT 'číslo typu výrobku',
`id_material` int(11) NOT NULL COMMENT 'číslo materiálu z ceníku',
`item_count` int(11) NOT NULL DEFAULT '1' COMMENT 'počet jednotek',
`price_cost` decimal(14,2) NOT NULL COMMENT 'nákladová cena',
`price_sale` decimal(14,2) NOT NULL COMMENT 'prodejní cena',
PRIMARY KEY (`id`),
KEY `cl_types_id` (`cl_types_id`),
KEY `offers_main_id` (`offers_main_id`),
KEY `id_firm` (`id_firm`),
KEY `offers_group_id` (`offers_groups_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
--
-- Vypisuji data pro tabulku `offers_items`
--
INSERT INTO `offers_items` (`id_firm`, `offers_main_id`, `offers_groups_id`, `id`, `label_item`, `cl_types_id`, `id_material`, `item_count`, `price_cost`, `price_sale`) VALUES
(1, 1, 1, 1, 'první položka ', 10, 0, 12, '0.00', '0.00'),
(1, 1, 1, 2, 'druhá položka', 1, 0, 2, '0.00', '0.00'),
(1, 1, 26, 3, 'třetí položka', 1, 0, 1, '0.00', '0.00'),
(1, 1, 26, 4, 'čtvrtá položka', 1, 0, 1, '0.00', '0.00'),
(1, 1, 1, 6, 'další třetí', 1, 0, 1, '0.00', '0.00'),
(1, 1, 1, 7, 'aaa', 1, 0, 1, '0.00', '0.00');
-- --------------------------------------------------------
--
-- Struktura tabulky `offers_items_parameters`
--
CREATE TABLE IF NOT EXISTS `offers_items_parameters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_firm` int(11) NOT NULL COMMENT 'číslo firmy',
`offers_items_id` int(11) NOT NULL COMMENT 'číslo položky',
`cl_parameters_id` int(11) NOT NULL COMMENT 'číslo parametru',
`value_parameter` varchar(20) NOT NULL COMMENT 'hodnota parametru',
PRIMARY KEY (`id`),
KEY `id_firm` (`id_firm`),
KEY `offers_item_id` (`offers_items_id`),
KEY `cl_parameters_id` (`cl_parameters_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='parametry položky' AUTO_INCREMENT=3 ;
--
-- Vypisuji data pro tabulku `offers_items_parameters`
--
INSERT INTO `offers_items_parameters` (`id`, `id_firm`, `offers_items_id`, `cl_parameters_id`, `value_parameter`) VALUES
(1, 1, 2, 2, ''),
(2, 1, 2, 2, '');
--
-- Omezení pro exportované tabulky
--
--
-- Omezení pro tabulku `cl_types_parameters`
--
ALTER TABLE `cl_types_parameters`
ADD CONSTRAINT `cl_types_parameters_ibfk_2` FOREIGN KEY (`cl_parameters_id`) REFERENCES `cl_parameters` (`id`),
ADD CONSTRAINT `cl_types_parameters_ibfk_3` FOREIGN KEY (`cl_types_id`) REFERENCES `cl_types` (`id`) ON DELETE CASCADE;
--
-- Omezení pro tabulku `offers_items`
--
ALTER TABLE `offers_items`
ADD CONSTRAINT `offers_items_ibfk_3` FOREIGN KEY (`cl_types_id`) REFERENCES `cl_types` (`id`),
ADD CONSTRAINT `offers_items_ibfk_4` FOREIGN KEY (`offers_main_id`) REFERENCES `offers_main` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `offers_items_ibfk_5` FOREIGN KEY (`offers_groups_id`) REFERENCES `offers_groups` (`id`) ON DELETE CASCADE;
--
-- Omezení pro tabulku `offers_items_parameters`
--
ALTER TABLE `offers_items_parameters`
ADD CONSTRAINT `offers_items_parameters_ibfk_2` FOREIGN KEY (`cl_parameters_id`) REFERENCES `cl_parameters` (`id`),
ADD CONSTRAINT `offers_items_parameters_ibfk_1` FOREIGN KEY (`offers_items_id`) REFERENCES `offers_items` (`id`) ON DELETE CASCADE;
- TomasHalasz
- Bronze Partner | 79
No a to je právě divné. Opravdu mám v template default.latte jen tenhle kód:
{foreach $Items_radek->related('offers_items_parameters') as $Parameters_radek2}
<tr>
<td>{$Parameters_radek2->cl_parameters->label_parameter}</td>
{/foreach}
A Ladenka říká chybu Invalid argument supplied for foreach() na řádku 65:
63: <?php $iterations = 0; foreach ($Items_radek->related('offers_items_parameters') as $Parameters_radek2): ?>
64: <tr>
65: <td><?php echo Nette\Templating\Helpers::escapeHtml($Parameters_radek2->cl_parameters->label_parameter, ENT_NOQUOTES) ?></td>
66: <?php $iterations++; endforeach ?>
Stejný způsob používám v té vazbě radek_z_tabulky_cl_types_parameters->cl_parameters->label_parameter viz. výše a tam to funguje.
- TomasHalasz
- Bronze Partner | 79
Připadá mi to nějaké divné. Když zkusím zrušit foreign key z tabulky
offers_items_parameters na cl_parameters tak dostanu logicky
na řádku 65 tuto chybu:
No reference found for
$offers_items_parameters->cl_parameters
Jakmile foreign key vytvořím takto:
ALTER TABLE `offers_items_parameters` ADD FOREIGN KEY ( `cl_parameters_id` ) REFERENCES `kalkulator`.`cl_parameters` (
`id`
);
tak dostanu na řádku 65 chybu:
Invalid argument supplied for foreach()
- TomasHalasz
- Bronze Partner | 79
vvoody napsal(a):
Metodu ref(‚tabulka2‘,‚FK_v_tabulke1‘) mozes pouzit kedykolvek. Zapis $riadokVTabulke1->tabulka2 je len alternativa k ref ktora funguje len ak su dodrzane iste konvencie pomenovania FK.
Zkusil jsem použít ref() a hlásí to stejnou chybu jako když mám přímý zápis. Udělal jsem to takto:
{$Parameters_radek2->ref('cl_parameters','cl_parameters_id')->label_parameter}
- TomasHalasz
- Bronze Partner | 79
Asi jsem lama, ale kde mám udělat ten dump když to je v šabloně? $this->rows mi v šabloně nejde.
- TomasHalasz
- Bronze Partner | 79
Tak už jsem přišel na to jak chybu 100% vyvolat a jak ji obejít :-)
K chybě Invalid argument supplied for foreach() dojde tehdy pokud použiju v template vnořený foreach s related takto:
{foreach $OffersItems as $Items_radek}
..
..
{foreach $Items_radek->related('offers_items_parameters') as $Parameters_radek2}
{* zde už nemůžu použít následující konstrukci
na jejím řádku dojde k chybě Invalid argument supplied for foreach() *}
{$Parameters_radek2->cl_parameters->id}
{/foreach}
{/foreach}
Jakmile si nachystám data v presenteru:
$this->template->ParamItems_radek=$this->context->createOffersItemsParameters()->where("id_firm", $this->section->id_firm);
Tak v šabloně toto funguje
{foreach $OffersItems as $Items_radek}
..
..
{foreach $ParamItems_radek->where('offers_items_id', $Items_radek->id) as $Parameters_radek2}
{$Parameters_radek2->cl_parameters->id};</td>
{/foreach}
{/foreach}
Je to chyba moje nebo nette?
- hrach
- Člen | 1838
Tento kod jsem plne vyzkousel na tvym sql dumpu. Jedna se o klasickou vazbu M:N a mne plne funguje i se zapnutou cache.
{foreach $OffersItems as $Items_radek}
..
..
{foreach $Items_radek->related('offers_items_parameters') as $Parameters_radek2}
{* zde už nemůžu použít následující konstrukci
na jejím řádku dojde k chybě Invalid argument supplied for foreach() *}
{$Parameters_radek2->cl_parameters->id}
{/foreach}
{/foreach}
Asi si chybu spatne analyzoval. Jakou mas verzi PHP?
- TomasHalasz
- Bronze Partner | 79
Mám PHP Version 5.3.6-pl1-gentoo
Jinak mi to dělá pořád… tak nevím… co je špatně.
- hrach
- Člen | 1838
Musis dany problem pokud mozno co nejvic izolovat. Zkus si vytvorit skript mimo tvuj projekt pracujici s danou db, v nem vytvorit spojeni (s cachi) a zkusit provest dane foreache…
require './../../../Nette/loader.php';
$storage = new Nette\Caching\Storages\FileStorage(__DIR__.'/../../tmp');
$connection = new Nette\Database\Connection('mysql:host=localhost;dbname=nette_test', 'root');
$connection->setCacheStorage($storage);
$connection->setDatabaseReflection(new Nette\Database\Reflection\DiscoveredReflection($storage));
Nette\Diagnostics\Debugger::enable(Nette\Diagnostics\Debugger::DEVELOPMENT);
$dbPanel = new Nette\Database\Diagnostics\ConnectionPanel;
$connection->onQuery[] = callback($dbPanel, 'logQuery');
Nette\Diagnostics\Debugger::$bar->addPanel($dbPanel);
...
- David Matějka
- Moderator | 6445
nejakej pokrok? taky jsem se setkal s timhle problemem.. vse je v poradku, pokud prvni zaznam ma tu podpolozku..
<?php
{foreach $OffersItems as $Items_radek}
..
..
{foreach $Items_radek->related('offers_items_parameters') as $Parameters_radek2}
{* kdyz prvni $Items_radek nema nic v offers_items_parameters a dalsi uz jo, tak to skonci na tej chybe....*}
{/foreach}
{/foreach}
?>
jelikoz nekde tady https://api.nette.org/…ion.php.html#62 (a mozna i jinde) dojde k vymazani $this->rows…
- TomasHalasz
- Bronze Partner | 79
Mě to dělá pořád stejně. Bohužel jsem na to neměl více času a musel jsem pokročit dál tak jsem to obešel jinudy. Jakmile budu mít chvilku tak to zkusím vyvolat v samostatném scriptu ať je to čítelnější…
- David Matějka
- Moderator | 6445
tak tahle chyba je opravena ve vetvy od hracha ( https://github.com/…-refactoring ), pokud jste na standardni verzi nette\database, tak by to mel resit tenhle commit https://github.com/…ae3086c8cc6c
- tomask
- Člen | 9
Potvrzuji, že jsem v Nette 2.0.4 zaznamenal zde popisovaný problém. Jednalo se o totožný příklad, jako je v dokumentaci, tedy:
{foreach $database->table('book')->order('title')->limit(5) as $book}
<h2>{$book->title} ({$book->author->name})</h2>
{foreach $book->related('book_tag') as $book_tag}
{$book_tag->tag->name}{sep}, {/sep}
{/foreach}
{/foreach}
Uvedený příklad funguje v pořádku, když pro první knihu/iteraci jsou v databázi related book_tagy. V případě, že první kniha má nula related book_tagů, tak se opravdu objeví notice s foreachem.
Odkazovaný patch https://github.com/…ae3086c8cc6c problém řeší.