Jednoduchý seorouter nemá přístup k instanci třídy z modelu

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

Ahoj,
snažím se nastavit seo routování podle db (název firmy místo ID do adresy) – co nejjednodušeji, pro začátek, bez zbytečných tříd navíc, přes to, to začíná být pěkně složité (konstruováno podle přednášky https://www.youtube.com/watch?… a možná něco málo ze zdejší diskuze):

  1. zjistil jsem, že musím vytvořit novou routu v bootstrap.php:
<?php
$firmy=$container->firmy;
$router[] = new Model\BazarRoute('bazar/<bazar>',array(
    'module'=>'Front',
    'presenter'=>'Inzeraty',
    'action'=>'bazar',
    'bazar'=>array(0=>array(
        Route::FILTER_IN => function($bazar) use ($container){
          if(is_numeric($bazar)){
              return $bazar;
          }
          else{
              return $firmy->getIdBySeo($bazar);

          }
        },
        Route::FILTER_OUT =>function($bazar) use ($container){
            if(!is_numeric($bazar)){
                return $bazar;
            }else{
               return $firmy->getSeoById($bazar);
            }
        }
    )
),$firmy));
?>
  1. pro tuto routu jsem tedy vytvořil novou třídu BazarRoute:
<?php
class BazarRoute extends \Nette\Application\Routers\Route{
    private $firmy;
public function __construct($mask, $metadata = array(), $flags = 0,\Model\AdminModule\Firmy $firmy){
        parent::__construct($mask, $metadata = array(), $flags = 0);
        $this->firmy=$firmy;
    }
    public function injectUsersModels(\Model\AdminModule\Firmy $firmy)
    {
        $this->firmy=$firmy;
    }
    public function match(\Nette\Http\IRequest $request){
        $appRequest = parent::match($request);
        if(!is_numeric($appRequest->parameters['bazar'])){
            $page = $this->firmy->getIdBySeo($appRequest->parameters['bazar']);
            if($page==NULL){
                return NULL;
            }
            $appRequest->parameters['bazar']=array(0=>$page);
        }
        return $appRequest;
    }
}
?>

(zbytek je ozkoušený že funguje, tedy nebudu uvádět)
v configu mám

<?php
services:
        firmy: Model\AdminModule\Firmy
?>

Nová třída BazarRoute přesto nemá přístup k \Model\AdminModule\Firmy $firmy (chyba Call to a member function getIdBySeo() on null) – nepomáhá construct, nepomáhá inject. Podle toho co jsem vyčetl: ve chvíli kdy žádám instanci této třídy při vytváření BazarRoute, tak třída ještě není zavedena, zavede se až později. Nicméně ve filtrech při vytváření této BazarRoute už mám tu samou třídu dostupnou a vrátí správná data (jelikož parametry v této metodě se spouští asi později). Dokonce u mě nefunguje ani předání hodnoty tak jako na videu – tedy přes context (nebo jde o to že nepředávám databázi, měl jsem dojem, že bude třída jako třída a raději bych předával nějakou vyšší třídu). Takže fajn, instance není v této chvíli vytvořena, ale tím jsem se zasekl na mrtvém bodě pročítajíc diskuze pořád dokola(včetně https://forum.nette.org/…jeni-v-route kde Filip Procházka myslím radí jak na to – nicméně po realizaci jsem měl o jednu třídu (tedy v začátku potenciální problém) navíc a stále neexistující instanci). Poradí někdo jak dostat instanci třídy z modelu do třídy která vytváří Route()?
Edit
Něco jsem přehlédl a dle přednášky to vypadá, že to funguje… Nicméně i z té přenášky vyplývá, že tohle není úplně košér řešením tkaže jak je to správně?

Děkuji

Editoval argosovo (22. 9. 2015 17:43)

Darkling
Člen | 35
+
0
-

Ahoj, routy nevytvarej přímo v bootstrap, ale v nějaké jiné třídě RouterFactory, do té třídy si pak můžeš snadno předávat závislosti přes konstruktor. Inspiraci můžeš najít v nette sandbox viz odkaz dole, jenom ji pak nezapomeň zaregistrovat v configu opět viz nette sandbox.
https://github.com/…rFactory.php

chemix
Nette Core | 1310
+
+1
-

Narazil jsem vcera na pekny clanek : http://petrjirasek.cz/…lani-v-nette

argosovo
Člen | 54
+
0
-

Děkuji za rady, článek jsem přečetl a zjistil nějaké užitečné informace, nicméně nejdříve jsem se vydal cestou vytvoření vlastního routeru, upravil jsem defaultní router factory tak, že mé routy se načítají tam.
Co nefunguje a pořád nechápu, jak docílit aby fungovalo, je načítání jiných tříd z modelu do této RouterFactory. Vše funguje dokud nevytvořím konstruktor:

<?php
namespace App;

use Nette,
	Nette\Application\Routers\RouteList,
	Nette\Application\Routers\Route,
	Nette\Application\Routers\SimpleRouter;

class RouterFactory
{

	/**
	 * @return \Nette\Application\IRouter
	 */
        public function __construct(){

        }
	public function createRouter()
	{
            $router = new RouteList();
 /* $bazarRoute=new \Model\BazarRoute('bazar/<bazar>',array(
    'module'=>'Front',
    'presenter'=>'Inzeraty',
    'action'=>'bazar',
    'bazar'=>array(0=>array(
        Route::FILTER_IN => function($bazar) use ($container){
          if(is_numeric($bazar)){
              return $bazar;
          }
          else{
              return $firmy->getIdBySeo($bazar);

          }
        },
        Route::FILTER_OUT =>function($bazar) use ($container){
            if(!is_numeric($bazar)){
                return $bazar;
            }else{
               $firmy=$container->firmy;
               return $firmy->getSeoById($bazar);
            }
        }
    )
    )));*/

	$router[] = new Route('<presenter>/<action>/<id>', array(
    'module' => 'Front',
    'presenter' => 'Homepage',
    'action' => 'default',
    'id' => NULL,
));
return $router;
	}

}

?>

pro úplnost (z bootstrapu zmizelo úplně vše co se routeru týká) a v configu mám:
<?
services:
router: App\RouterFactory::createRouter
?>

vyhodí mi to error: Type of service ‚routing.router‘ is unknown.
Přemýšlel jsem, zda třeba RouterFactory nemá něco dědit, implementovat atp., takže po různých pokusech, je výsledek stále stejný… jakmile konstruktor odeberu vše začne zase fungovat…
jenže pokud nevytvořím konstruktor, neumím třídě předat instanci Třídy která překládá seo->id a zpět. Jak na to?

David Matějka
Moderator | 6445
+
0
-

ten phpdoc blok s @return musi byt nad metodou createRouter, ne nad konstruktorem

argosovo
Člen | 54
+
0
-

Děkuji moc, už to funguje… je k tomu někde nějaká vysvětlivka, proč php poznámka ovlivňuje chování celého frameworku?

Mám pocit, že jsem tak půl roku zpátky četl něco o injection pomocí poznámky a že to i fungovalo, nicméně tady se nic neinjektuje, pouze označuje co se vrátí a přes to to má vliv…
Ještě jednou děkuji všem

Unlink
Člen | 298
+
0
-

Ono to nieje poznámka, tie sú v php pomocou // a /* */
Tamto sa volá dokumentačný komentár (je v tom rozdiel, pretože dokumentačné komentáre je možné čítať aj v kode)

PHP je jazyk aký je, (do verzie 7) nemá return typy, to znamená že php ti priamo neposkytuje možnosť zistiť čo vráti volanie nejakej funkcie / metódy. V php sa toto rieši spracovávaním dokumentačných komentárov (nette/reflection).

Nette využíva dependency injection a keď napríklad registruješ ten router do kontajnera nejako takto

router: @petrjirasek\Routers\RouterFactory::createRouter

tak mu vlastne povieš že chceš mať službu s názvom router, ktorú vyrobí tak že zavolá createRouter ale nikde mu tu nehovoríš akého typu bude tá služba. On si podľa toho komentáru zistí že to bude typu
\Nette\Application\IRouter

David Matějka
Moderator | 6445
+
0
-

Jeste doplnim, ze ty phpdoc nejsou v tomto pripade povinny, ale zjednodusuji nasledny zapis v neonu, bez nich bych musel zapsat:

router:
	create: @Foo\Bar\RouterFactory:createRouter
	class: Nette\Application\IRouter
Azathoth
Člen | 495
+
0
-

běžné komentáře číst nejde, ale když máš phpdoc, tedy začátek komentáře je /**, a uvnitř toho phpDocu začíná komentář zavináčem, je to anotace a ta se běžně používá v php. zde je slideshare o anotacích , tady je ukázka, jak je číst přes reflexi a Doctrine/Annotations poskytují asi nejmocnější nástroje pro práci s anotacemi v php

Azathoth
Člen | 495
+
0
-

anotace jsou nejčastěji právě k tomu, aby dohnaly, co php neumí jako jazyk (např. return typy u továren, jako zde), a nebo k dodání nějaké informace navíc (@persistent u proměnných, @inject u služeb, apod.)