registerHelperLoader() se dožaduje onPrepareFilters()

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

Zdravím,

nejsem si jistý, jestli jde o bug nebo o undocumented feature, každopádně by bylo vhodné na to alespoň upozornit. V presenteru volám $template->registerHelperLoader('KAdm\CustomHelpers::register') na zaregistrování helperů, které fungují v pořádku. Avšak pokud třídu KAdm\CustomHelpers extenduji od Nette\Object, dočkám se tohoto:

Call to undefined static method KAdm\CustomHelpers::onpreparefilters().

Inu dobrá, definuji statickou metodu onPrepareFilters() a prázdnou, jelikož mě nenapadá, co jiného by tam mělo být. Excepšna zmizí, aplikace doběhne, ale bez Latte filteru (který jinak startuje automaticky). Co s tím? Prozatím tiše ignoruji volání neexistující statické metody prostým zakomentováním dědění od Nette\Object.

Používám jednu z posledních revizí Nette 1.0-dev na PHP 5.3.

David Grudl
Nette Core | 8228
+
0
-

$onPrepareFilters je proměnná definovaná v šabloně. Je to pole callbacků, které se zavolají přes $template->onPrepareFilters(). Jakým způsobem ti to koliduje netuším…

leumas
Člen | 13
+
0
-

Pozorujem rovnake chovanie, Template.php skutocne vola onPrepareFilters(), toto volanie zachyti __call z BaseTemplateu a zavola invokeArgs, ktory si mysli, ze sa jedna o helper.

# Nette Framework 0.9.5 (revision 5eb03f5 released on 2010–07–01)

Jan Tvrdík
Nette guru | 2595
+
0
-

Při pohledu do zdrojových kódů jsem došel k názoru, že máte blbě napsaný HelperLoader. Příklad jednoduché implementace se nachází i v dokumentaci.

leumas
Člen | 13
+
0
-

HelperLoader mam napisany presne podla prikladu v dokumentacii s jedinym rozdielom: dedim od Objectu (propaganda \Nette\Objectu ako prapredka vsetkeho na mna zjavne zabrala;-)) A to je zdroj problemov. Funkcia isCallable je naimplementovana ako phpckovske is_callable, ktore vracia vzdy true v pripade, ze trieda obsahuje __call metodu. Kedze je vsak trieda zdedena od Objectu, magic __call obsahuje a Helper sa preto tvari, ze danu metodu obsahuje a vrati jej callback.

Ono, chcelo by to asi, aby phpcko malo nejaku magic metodu __isCallable. Do dokumentacie by som navrhoval pridat k prikladu varovanie ludi pred implementovanim __call metody, ci dedenim z Objectu.

leumas
Člen | 13
+
0
-

Mimochodom, preco helperLoader dostava lowercase nazov metody, ktoru treba zavolat? Je to pomerne neprijemne, ak pouzivam helpery s camelcase.

Sorry, moja chyba, funkcie v php su narozdiel od premennych case insensitive, takze to neprekaza. Ten jazyk ma stale prekvapuje…

Editoval leumas (3. 9. 2010 14:30)

arron
Člen | 464
+
0
-

Myslim, ze jsem podobny problem resil nedavno. Jestli si dobre pamatuju, tak to bylo tim, ze trida s helpery mi delila od Object. Pak jsem dostaval presne tuhle chybu. Odstranenim dedeni se problem vyresil.

Editoval arron (3. 9. 2010 12:45)

leumas
Člen | 13
+
0
-

arron napsal(a):

Myslim, ze jsem podobny problem resil nedavno. Jestli si dobre pamatuju, tak to bylo tim, ze trida s helpery mi delila od Object. Pak jsem dostaval presne tuhle chybu. Odstranenim dedeni se problem vyresil.

No ano, ako vravim, je to sposobene tym, ze Object implementuje magic __call a tym padom funkcia is_callable vyhodnoti vsetky callbacky na danej triede ako callable, tj. vzdy vrati true.

Jan Tvrdík
Nette guru | 2595
+
0
-

Pokud je definované metoda __call tak nesmíte použít funkci is_callable, ale nahraďte ji funkcí method_exists.

arron
Člen | 464
+
0
-

leumas napsal(a):

No ano, ako vravim, je to sposobene tym, ze Object implementuje magic __call a tym padom funkcia is_callable vyhodnoti vsetky callbacky na danej triede ako callable, tj. vzdy vrati true.

Ech, malo ctu a brzo pisu. Pardon;-) Nicmene zrovna v pripade toho helperu je IMHO naprosto zbytecne dedit od Object (tez jsem podlehnul, nicmene se ukazuje, ze vsechno je potreba delat s rozvahou;-))

Bernard Williams
Člen | 207
+
0
-

Nazdárek,

neporadil by mi někdo nějaký rychlý fix, aby mi Nette pro verzi PHP 5.2 jelo na verzi PHP 5.3? Teď mi Nette háže chybu: Call to undefined static method Helpers::onpreparefilters()

Call stack:

  • 1. inner-code Object:: __callStatic
  • 2. inner-code Helpers:: onpreparefilters
  • 3. Utils/Callback.php (112) source ▼ call_user_func_array
Line 107:        public function invokeArgs(array $args)
Line 108:        {
Line 109:            if (!is_callable($this->cb)) {
Line 110:                throw new InvalidStateException("Callback '$this' is not callable.");
Line 111:            }
Line 112:            return call_user_func_array($this->cb, $args);
Line 113:        }

Budu rád za každou radu.
Bernard

Ondřej Mirtes
Člen | 1536
+
0
-

Ahoj,
Nette pro PHP 5.2 je s PHP 5.3 plně kompatibilní, chyba bude na tvé straně. V Nette žádná třída Helpers není, předpokládám, že tuto chybu vyvolává tvůj kód. Ukaž nám celou stack trace a především poslední místo v ní, kde se ještě jedná o tvůj kód (před cestou do Nette).

Bernard Williams
Člen | 207
+
0
-

Díky z reakci. Obávám se, že chyba je opravdu na straně Nette. Pokud existuje cache, tak se webová stránka zobrazí. Pokud jej ale smažu, tak to hodí chybu.

Jo a když se pokusím zobrazit jinou stránku než index, tak to hodí chybu 404, což na PHP 5.2.5 taky nedělá.

bojovyletoun
Člen | 667
+
0
-
  • dumpnul bych $this->helpers.
  • pak bych sledoval this->cb.
  • je správně onPrepareFilters s velikostí písmen? Dle mě se tady už jeden bug(php dokonce 5.2) řešil v souvislosti s PDO a Nette\Database a onquery zde
  • což potvrzuje původní podzření, že php 5.2 je na objekty málo vyzrálé

PS: kdo bude uvádět při sčítání lidu víru Nette framework?

Editoval bojovyletoun (2. 3. 2011 23:42)

Bernard Williams
Člen | 207
+
0
-

V souboru Utils/Callback.php na řádku return call_user_func_array($this->cb, $args); proměnná this->cb obsahuje:

array(2) [
   0 => "Helpers" (7)
   1 => "onpreparefilters" (16)
]

V souboru Templates/Template.php na řádku return $this->helpers[$lname]->invokeArgs($args); proměnná $this->helpers obsahuje:

array(10) {
   "escape" => Callback(1) {
      "cb" private => "TemplateHelpers::escapeHtml" (27)
   }
   "escapeurl" => Callback(1) {
      "cb" private => "rawurlencode" (12)
   }
   "striptags" => Callback(1) {
      "cb" private => "strip_tags" (10)
   }
   "nl2br" => Callback(1) {
      "cb" private => "nl2br" (5)
   }
   "substr" => Callback(1) {
      "cb" private => "iconv_substr" (12)
   }
   "repeat" => Callback(1) {
      "cb" private => "str_repeat" (10)
   }
   "replacere" => Callback(1) {
      "cb" private => "String::replace" (15)
   }
   "implode" => Callback(1) {
      "cb" private => "implode" (7)
   }
   "number" => Callback(1) {
      "cb" private => "number_format" (13)
   }
   "onpreparefilters" => Callback(1) {
      "cb" private => array(2) [
         0 => "Helpers" (7)
         1 => "onpreparefilters" (16)
      ]
   }
}

$lname obashuje:

"onpreparefilters" (16)

$args obsahuje:

array(1) [
   0 => FileTemplate(7) {
      "file" private => "C:\WWW\www.maturitni-tabla.cz\Web/app/FrontModule/templates/Homepage/default.phtml" (82)
      "warnOnUndefined" => TRUE
      "onPrepareFilters" => array(1) [
         0 => Callback(1) { ... }
      ]
      "params" private => array(11) {
         "control" => Front_HomepagePresenter(33) { ... }
         "presenter" => Front_HomepagePresenter(33) { ... }
         "user" => User(8) { ... }
         "baseUri" => "/www.maturitni-tabla.cz/Web/" (28)
         "basePath" => "http://localhost/www.maturitni-tabla.cz/Web" (43)
         "flashes" => array(0)
         "login_form" => AppForm(17) { ... }
         "tabla" => DibiResult(6) { ... }
         "layout" => "C:\WWW\www.maturitni-tabla.cz\Web/app/templates/@layout.phtml" (61)
         "_extends" => "C:\WWW\www.maturitni-tabla.cz\Web/app/templates/@layout.phtml" (61)
         "template" => FileTemplate(7) { *RECURSION* }
      }
      "filters" private => array(0)
      "helpers" private => array(10) {
         "escape" => Callback(1) { ... }
         "escapeurl" => Callback(1) { ... }
         "striptags" => Callback(1) { ... }
         "nl2br" => Callback(1) { ... }
         "substr" => Callback(1) { ... }
         "repeat" => Callback(1) { ... }
         "replacere" => Callback(1) { ... }
         "implode" => Callback(1) { ... }
         "number" => Callback(1) { ... }
         "onpreparefilters" => Callback(1) { ... }
      }
      "helperLoaders" private => array(2) [
         0 => Callback(1) { ... }
         1 => Callback(1) { ... }
      ]
   }


Nějak vůbec nevím co s tím :-/
]
Ondřej Mirtes
Člen | 1536
+
0
-

Nekde ve svem kodu si registrujes callback Helpers::onPrepareFilters(), ktery ovsem neexistuje.

Bernard Williams
Člen | 207
+
0
-

To já nedělám, to dělá Nette – celý Call stack je z Nette.. A i kdybych Helpers::onPrepareFilters() definoval sám, nemyslíš, že by to pak nejelo ani na PHP 5.2? Nejspíš ne, že? Ale ono jede.. takže chyba bude někde ve způsobu volání.. se kterým si PHP 5.3 neumí poradit.. a já bohužel nemůžu přijít na to kde a už vůbec ne na to, jak to opravit :-/

Jan Tvrdík
Nette guru | 2595
+
0
-

Začni tím, že si projdeš všechny výskyty řetězce onPrepareFilters v celém projektu.

Ondřej Mirtes
Člen | 1536
+
0
-

Když v aktuálním Nette sandboxu vydumpuju $template->getHelpers(), je jich tam jen devět. Ten desátý si opravdu registruješ sám a pravděpodobně nějakým způsobem, který na PHP 5.2 funguje, ale na 5.3 ne.

Zkus na svůj projekt pustit fulltextové hledání „registerHelperLoader“ a „registerHelper“ a uvidíš.

Bernard Williams
Člen | 207
+
0
-

Chlapi, smekám.

onPrepareFilters bylo jen v Nette, ale při zakomentování registerHelperLoader to fungovalo. Při bližším zkoumání byl problém ve scriptu Helpers s definicí jednotlivých helprů. Konkrétně bylo potřeba místo:

$callback = callback(__CLASS__, $helper);
if ($callback->isCallable()) {
    return $callback;
}

dát:

if (is_callable($callback = __CLASS__ . '::' . $helper))
    return $callback;

což funguje jak na PHP 5.3, tak i na PHP 5.2.

Mockrát všem děkuji!

Milo
Nette Core | 1283
+
0
-

Právě jsem se setkal s tou samou chybou u aktuální verze Nette z Githubu. Migroval jsem aplikaci z 5.2 na 5.3. Jak je výše uvedeno, chyba vznikne při dědění z Nette\Object.

// Starý helper loader
class Helpers extends Nette\Object
{
	public static function loader($helper)
	{
		if (is_callable(__CLASS__ . '::' . $helper))	// vždy TRUE, protože Object implementuje __callStatic()
		{
			return callback(__CLASS__, $helper);
		}
		return NULL;
	}
}

// Funkční nová verze
class Helpers extends Nette\Object
{
	public static function loader($helper)
	{
 		if (method_exists(__CLASS__, $helper))
 		{
 			return callback(__CLASS__, $helper);
 		}
		return NULL;
	}
}

Zvláštní (side effect?) je, že metoda Helpers::loader() je volána s parametrem onpreparefilters. Někde se tedy zavolá Helpers::loader('onpreparefilters') a to asi tady a to pouze při kompilaci šablony. Má to nějaký důvod?