Jak odhalit chybu

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Laethnes
Člen | 53
+
0
-

Omlouvám se, že zase otravuju se svými chybami, ale nějak si s tím nevím rady.
Mám formulář, který obsahuje checkbox. Když jej zaškrtnu a odešlu, zobrazí se jen prázdná stránka a té se na dané adrese nezbavím, dokud nesmažu cache. Do šablony se ale kód nedostane, protože používám po uložení dat v presenteru redirect. Laděnka funguje – otestoval jsem na jiné výjimce. Jediné, co jsem zjistil bylo v logu serveru: access.log:

127.0.0.1 – – [01/Aug/2009:12:05:28 +0200] „GET /MojeTvorba/Nette/administration/menu.php HTTP/1.1“ 500 –

Kód vypadá asi takto (v presentru):

<?php
$form = new Form("menu_form");
// pridam polozky
// ...
$form->addCheckbox("show", "zobrazit v menu");

if($form->isSubmitted())
{
	if($form->isValid())
	{

		$values = $form->getValues();

		$query_data = array(
			"presenter" => $values["presenter"],
			"name" => $values["name"],
			"role" => $values["role"]
			);

		// Kdyz zakomentuju nasledujici 4 radky, vse je OK (ale samozrejme se neulozi data o show)
		if($values["show"])
			$query_data["show"] = 1;
		else
			$query_data["show"] = 0;

		dibi::query("INSERT INTO menu", $query_data);

		$this->redirect("this", array("edit_id" => 0));
	}
}
?>

Nevíte, v čem dělám chybu, nebo jak ji zjistit?

Edit:

Nette pro PHP 5.2.0 r.464

Editoval Laethnes (1. 8. 2009 12:45)

jasir
Člen | 746
+
0
-

V presenteru nepoužívej Form, ale AppForm.
Nějak takto (Nette 0.9)

<?php

class MyPresenter extends Presenter {
	protected function createComponentMyForm() {
		$form = new AppForm;
		$form->addText(...);
		$form->addCheckBox(...);
		$form->addSubmit('submit1','Odešli');
		$form->onSubmit[] = array($this,'myFormSubmitted');
		return $form;
        }

	public function myFormSubmitted($form) {
		$values = $form->getValues();
		..
		$this->redirect(...);
	}
}
?>

Editoval jasir (1. 8. 2009 12:51)

Laethnes
Člen | 53
+
0
-

jasir napsal(a):

V presenteru nepoužívej Form, ale AppForm.

Nic se nezměnilo, pořád ta samá chyba…

Edit:

Ještě bych měl dodat, že příkaz dibi::query(…) se provede – záznam v databázi se objeví. Pak už je jen ten redirect, ale ověřil jsem si, že před ním nepošlu žádná data (jak jeho zrušením a odesláním dat, tak pomocí ob_start()).

Editoval Laethnes (1. 8. 2009 13:18)

jasir
Člen | 746
+
0
-

Hmm, je to divný. Může to být tou 5.2.0, viz tady. To, že nereaguje laděnka napovídá nějaké nestandartní problémy.
Předpokládám, že chyba se projeví, i když odstraníš ten redirect?

Edit: Aha, ty nepíšeš, že máš verzi php 5.2.0 ale že máš Nette pro 5.2.0. Jaké máš tedy php?

Editoval jasir (1. 8. 2009 13:25)

Laethnes
Člen | 53
+
0
-

jasir napsal(a):

Hmm, je to divný. Může to být tou 5.2.0, viz tady. To, že nereaguje laděnka napovídá nějaké nestandartní problémy.
Předpokládám, že chyba se projeví, i když odstraníš ten redirect?

Edit: Aha, ty nepíšeš, že máš verzi php 5.2.0 ale že máš Nette pro 5.2.0. Jaké máš tedy php?

Bacha na to – používám Nette pro PHP 5.2.0 (protože aplikaci budu používat na serveru s PHP 5.2.0) a doma mám PHP 5.2.8.
Když odstraním ten redirect, tak stránka se ještě zobrazí, ale když ji dám zobrazit znovu (pochopitelně URL upravím tak, aby tam jiz nebyla dana akce), tak je to klasická chyba. Ano, to napovídá, že chyba je mimo zmíněný kód – a to nepopírám – ale když odstraním řádky, které jsem v prvním příspěvku označil, vše je bez problémů…

Editoval Laethnes (1. 8. 2009 13:33)

Laethnes
Člen | 53
+
0
-

Tak jsem poodhalil v čem to může být a kupodivu to vypadá na chybu v Nette nebo PHP, i když mě to přijde divné. V tom formuláři to není, spíš jde o to, co dělá – jedná se o to, že se mě nechtělo menu psát ručně, ale generovat z databáze (pro možnost mít více vzhledů stránek) a také proto, abych mohl ověřovat přístupová práva, která snadno změním právě v databázi skrz nějaký formulář.

To políčko „show“ je, zda je položka vidět nebo ne (to pro kontrolu presenterů, na které budu odkazovat, ale ne z menu). A ta chyba vznikla tehdy, když jsem zadal neexistující presenter a zároveň jeho zobrazení, při tvorbě menu se vyvolal následující kód:

<?php
...{plink "neexistujici_presenter:"}...
?>

Jak jsem již dříve zjistil, Nette se pokusí nahrát daný presenter (což mě tak trochu štve – proč pokaždé, když tvořím odkaz se musí nahrát i ten presenter, i když jinak nebude používán?) a zde zkolabuje. Používám RobotLoader. Když jsem smazal cache, Nette se s tím vypořádalo a prostě vytvořilo odkaz „error: Cannot load…“ (ano, vím, že toto chování lze změnit). Když jsem však vytvořil novou položku do menu, celý systém vyvolal tu podivnou chybu, kdy se zobrazila prázdná stránka. Jenže, co s tím? To asi nebude standardní chování aplikace, že? Navíc mě stále přijde divné, že pak má aplikace problém zobrazit danou stránku se seznamem položek menu, ale přitom tam nemám žádný odkaz na víc a ostatní stránky fungují. Navíc jsem zjistil, že ani toto chování není 100% – občas se stane, že bílou stránku zobrazí i jiná kombinace presenter-view a naopak stránka s editací se občas zobrazí v pohodě. Když ale v menu nemám odkaz na neexistující presenter, vše je bez problémů…

Laethnes
Člen | 53
+
0
-

Ona ta chyba bude asi někde úplně jinde. Začala se mě objevovat znovu, tentokráte v šabloně. Stejné příznaky, situace:

Presenter:

<?php

$rights["add"] = $user->isAllowed(...);
$rights["del"] = $user->isAllowed(...);
$rights["edit"] = $user->isAllowed(...);

?>

Šablona:

<?php
$right_edit = $rights["edit"] ? true : false;
$right_add = $rights["add"] ? true : false;
$right_del = $rights["del"] ? true : false;

$alter = ($right_edit || $right_add || $right_del);
?>

Vše funguje. Přidám do šablony:

<?php

if($alter)
	echo "Nějaký text";

?>

bílá obrazovka. Neví někdo, jak hledat příčinu problému?

EDIT: jo, možná to je podstatné: pracuju ve Windows XP.

Editoval Laethnes (1. 8. 2009 17:51)

Laethnes
Člen | 53
+
0
-

Já už z toho nemožu :3. Trošku jsem udělal pár pokusů a zjistil jsem následující:

  • Server doma (PHP 5.2.8):
    • 0.9 dev (rev. 464 ze dne 24. 7. 2009)
      • Objevují se výše uvedené chyby
    • 0.8 stable (ze dne 5. 5. 2009)
      • Vše je OK
  • Server na IC.CZ (PHP 5.2.0)
    • 0.9 dev (rev. 464 ze dne 24. 7. 2009)
      • Vše je OK
    • 0.8 stable (ze dne 5. 5. 2009)
      • Objevuje se chyba, kterou jsem již řešil ale řešení v tomto fóru nepomohlo (žádnou výjímku nechytám). Chyba, která se vždy objevuje je ale jen 502.

To píšu tak zabuggované aplikace? Zas tak moc kódu tam nemám… Nebo je problém v Nette? Špatná konfigurace serveru? Kde mám začít hledat? Bez chybových hlášek a logů prostě nevím…

Jediné, co mě napadá, že by mohlo být zdrojem problémů (i když chyby s 502 jsem měl před tím, než jsem udělal následující) je to, že jsem si udělal soubor @layout.phtml nad všemi šablonami. Avšak chtěl jsem mít možnost více vzhledů, je v @layout.phtml následující:

<?php

// získá pole s daty s aktuálním vzhledem
$skin_data = CSkins::GetSingleton()->GetActualSkinData();

// vzhled je uložen v souboru, na kterém chci používat níže uvedený filtr,
// takže ho prostě nemůžu inkludovat, ale vytvořím novou šablonu.
$template = new Template();
$template->setFile(APP_DIR . "/skins/" . $skin_data["file"]);
$template->registerFilter(/*Nette\Templates\*/'CurlyBracketsFilter::invoke');

// Bohužel, nevím, jak zkopírovat data
$template->presenter = $presenter;
$template->control = $control;
$template->content = $content;
$template->baseUri = $baseUri;

// vykreslím soubor
echo $template;

?>

Jak vidno, nepodařilo se mě na netu zjistit, jak zkopírovat data tak, aby soubor šablony měl přístupné data jako @layout.phtml, takže jsem je prostě zkopíroval a mohlo mě něco uniknout. Ono to totiž vypadá (aspoň mě to tak přijde), že hlavní problém je na některých stránkách, které jsou možná závislé na některých datech šablony, které jsou takto neúplné/špatné.

Jinak, v šabloně konkrétního vzhledu mám mj. kód {$content->render()}, který renderuje hlavní data.

EDIT: (Pokaždné, když měním verzi Nette mažu temp a sessions adresáře.)

Editoval Laethnes (1. 8. 2009 19:26)

Papoušek
Člen | 16
+
0
-

OT: Nehodilo by se tohle spíš do nějakého BasePresenteru?

abstract class BasePresenter
{
	protected function createTemplate() {
		$template = parent::createTemplate();

		// Nastaveni skinu
		$skin_data = CSkins::GetSingleton()->GetActualSkinData();
		$template->setFile(APP_DIR . "/skins/" . $skin_data["file"]);

		// Nastaveni filtru
		$template->registerFilter(/*Nette\Templates\*/'CurlyBracketsFilter::invoke');

		return $template;
	}
}
Laethnes
Člen | 53
+
0
-

Papoušek napsal(a):

OT: Nehodilo by se tohle spíš do nějakého BasePresenteru?

Mno, popravdě řečeno mě to nenapadlo, nebo napadlo a zavrhl jsem to. Tak jsem to teď zkusil a někde je chyba, háže to výjimku „Call to a member function render() on a non-object“ na řádku ve vzhledu, kde je „$content->render()“. Obávám se (ale nevím to jistě, opravte mě někdo, pokud se mýlím), že šablona tvořená v presenteru skrz createTemplate() je šablona konkrétní stránky (presenter/view) a ne ta, která je vytvořena pro @layout, do nějž je formou proměnné $content vložena šablona stránky… nebo ne?

jasir
Člen | 746
+
0
-

Než dělat podobné brejkule v layoutu, dělej to spíš pomocí include:

BasePresenter:

<?php
protected function beforeRender() {
	$skin_data = CSkins::GetSingleton()->GetActualSkinData();
	$this->template->skinfile = APP_DIR . "/skins/" . $skin_data['file'];
}
?>

@layout.phtml:

{include $skinfile}

Editoval jasir (1. 8. 2009 20:01)

Papoušek
Člen | 16
+
0
-

Laethnes napsal(a):

Papoušek napsal(a):

OT: Nehodilo by se tohle spíš do nějakého BasePresenteru?

Mno, popravdě řečeno mě to nenapadlo, nebo napadlo a zavrhl jsem to. Tak jsem to teď zkusil a někde je chyba, háže to výjimku „Call to a member function render() on a non-object“ na řádku ve vzhledu, kde je „$content->render()“. Obávám se (ale nevím to jistě, opravte mě někdo, pokud se mýlím), že šablona tvořená v presenteru skrz createTemplate() je šablona konkrétní stránky (presenter/view) a ne ta, která je vytvořena pro @layout, do nějž je formou proměnné $content vložena šablona stránky… nebo ne?

Používám v šablonách dědičnost a neuvědomil jsem si to, máš asi pravdu.

V tom dědění by to mohlo vypadat nějak takto:

protected function createTemplate() {
	$this->oldLayoutMode = false;
	$template = parent::createTemplate();

        // Nastaveni skinu
	$skin_data = CSkins::GetSingleton()->GetActualSkinData();
	$template->skinFile = $skin_data["file"];

	...

        return $template;
}

A šablona view:

{extends $skinFile}
{content}...{/content}

Ale nezkoušel jsem to.

EDIT: To jasir: To je asi jednodušší.

Editoval Papoušek (1. 8. 2009 20:07)

Laethnes
Člen | 53
+
0
-

To jasir, Papoušek:
yay, moc díky za pomoc, já su fakt blb a Nette je mazec! Samozřejmě, {include „file…“} to vyřešilo – nevěděl jsem, že při takovémto inkludování přejdou filtry na inkludovaný soubor (To Papoušek: taky právěže používám filtry a dědičnost, i když tu trošičku jinak) a když jsem to psal, zkusil jsem <?php include(…); ?> a ne {include …}.

Nicméně to pořád neřeší ten problém z jiného fóra , kdy stejná chyba vzniká po té, co je cache Nette-loaderu nahrána již nějakou dobu vytvořena a vytvořím odkaz na neexistující presenter.

Moc moc vám všem díky za pomoc a rady ;)

Editoval Laethnes (1. 8. 2009 21:06)

PetrP
Člen | 587
+
0
-

Při řešení podobných chyb doporučuju následující postup: zmenšovat aplikaci tak dlouho dokud se chyba ještě projevuj a kód je co nejmenší. Během tohohle procesu bud sám zjistíš kde je chyba (pravděpodobnější) nebo tu zmenšeninu hodíš na fórum a mi si to můžem pustit a možná pomoct.