Routa pro presentery v libovolné namespace

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

Zkouším si vytvořit další z řady CMF a narazil jsem na problém. Chtěl bych vytvořit routu, která by spouštěla presentery z namespace CMF. Tzn použití by bylo takto:

$router[] = new CMFRoute('<presenter>/<action>[/<id>]', 'Front:Homepage:default');  //spustí se presenter \CMF\FrontModule\HomepagePresenter a jeho akce default

Zkoušel jsem to takto:

class CMFRoute extends Route
{
    public function match(IRequest $httpRequest)
    {
        $request = parent::match($httpRequest);
        $request->setPresenterName('CMF\\' . $request->getPresenterName());

        return $request;
    }
}

Ale evidentně na to jdu špatně.

Prosím o rady, odkazy apod. Z API na to nejsem schopný přijít. Díky

EDIT: Tak částečně vyřešeno (pohrabal jsem se uvnitř Nette). Budu muset přepsat službu presenterFactory (její metodu formatPresenterClass). Bohužel nevím, jak to mám udělat (čistě), aby byl výsledný namespace presenteru závislý na použité routě.

Editoval xxxObiWan (24. 7. 2011 20:59)

nanuqcz
Člen | 822
+
0
-

Tak nakonec jsem to vyřešil takhle (pokud to někomu pomůže):

config.neon

services:
    presenterFactory:   #přepisuji defaultní PresenterFactory z Nette
        class: MyPresenterFactory
        arguments: [%appDir%, @container]

MyPresenterFactory.php

class MyPresenterFactory extends Nette\Application\PresenterFactory
{

    /**
     * Podpora pro vlastní namespace presenterů
     * @param string $name
     * @return string
     */
    public function getPresenterClass(& $name)
    {
        if (strrpos($name, '\\')) {
            return $this->formatPresenterClass($name);  //obejdeme všechny kontroly Nette :-(
        } else {
            return parent::getPresenterClass($name);
        }
    }

}

bootstrap.php

$router[] = new NamespaceRoute('<presenter>/<action>[/<id>]', 'CMF\\Homepage:default');

NamespaceRoute.php

class NamespaceRoute extends Route
{
    /** @var string */
    protected $namespace;



    /**
     * @param string  URL mask, e.g. '<presenter>/<action>/<id \d{1,3}>'
     * @param array|string  default values or metadata
     * @param int flags
     */
    public function __construct($mask, $metadata = array(), $flags = 0)
    {
        if (is_string($metadata) && strrpos($metadata, '\\')) {
            $this->namespace = substr_replace($metadata, '', strrpos($metadata, '\\'));
            $metadata = substr_replace($metadata, '', 0, strrpos($metadata, '\\') + 1);
        } else {
            $this->namespace = '';
        }

        parent::__construct($mask, $metadata, $flags);
    }



    /**
     * Maps HTTP request to a Request object.
     * @param IRequest
     * @return Request|NULL
     */
    public function match(IRequest $httpRequest)
    {
        $request = parent::match($httpRequest);

        if ($request !== NULL && $this->namespace) {
            $request->setPresenterName($this->namespace . '\\' . $request->getPresenterName());
        }

        return $request;
    }



    /**
     * Constructs absolute URL from Request object.
     * @param Request
     * @param Url
     * @return string|NULL
     */
    public function constructUrl(Request $appRequest, Url $refUrl)
    {
        if ($this->namespace) {
            $nameWithoutNamespace = substr_replace($appRequest->getPresenterName(), '', 0, strlen($this->namespace) + 1);
            $appRequest->setPresenterName($nameWithoutNamespace);
        }

        return parent::constructUrl($appRequest, $refUrl);
    }

}

Nevím, nakolik je to čisté řešení (ale zatím vypadá že funguje). Za případné návrhy na lepší řešení předem děkuji :-)

Editoval xxxObiWan (26. 7. 2011 2:26)