Skip to content

Commit

Permalink
Merge pull request #66 from dg/pull-invalid
Browse files Browse the repository at this point in the history
PresenterFactory as callback & changed invalid link handling [WIP]
  • Loading branch information
dg committed Feb 25, 2015
2 parents b29b3db + 8c7648b commit 3c63c03
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 46 deletions.
35 changes: 8 additions & 27 deletions src/Application/PresenterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,16 @@ class PresenterFactory extends Nette\Object implements IPresenterFactory
/** @var array */
private $cache = array();

/** @var Nette\DI\Container */
private $container;
/** @var callable */
private $factory;

/** @var string */
private $touchToRebuild;


public function __construct(Nette\DI\Container $container, $touchToRebuild = NULL)
/**
* @param callable function(string $class): IPresenter
*/
public function __construct($factory = NULL)
{
$this->container = $container;
$this->touchToRebuild = $touchToRebuild;
$this->factory = $factory ?: function($class) { return new $class; };
}


Expand All @@ -50,25 +49,7 @@ public function __construct(Nette\DI\Container $container, $touchToRebuild = NUL
*/
public function createPresenter($name)
{
$class = $this->getPresenterClass($name);
$services = array_keys($this->container->findByTag('nette.presenter'), $class);
if (count($services) > 1) {
throw new InvalidPresenterException("Multiple services of type $class found: " . implode(', ', $services) . '.');

} elseif (!$services) {
if ($this->touchToRebuild) {
touch($this->touchToRebuild);
}

$presenter = $this->container->createInstance($class);
$this->container->callInjects($presenter);
if ($presenter instanceof UI\Presenter && $presenter->invalidLinkMode === NULL) {
$presenter->invalidLinkMode = $this->container->parameters['debugMode'] ? UI\Presenter::INVALID_LINK_WARNING : UI\Presenter::INVALID_LINK_SILENT;
}
return $presenter;
}

return $this->container->createService($services[0]);
return call_user_func($this->factory, $this->getPresenterClass($name));
}


Expand Down
20 changes: 10 additions & 10 deletions src/Application/UI/Presenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@
abstract class Presenter extends Control implements Application\IPresenter
{
/** bad link handling {@link Presenter::$invalidLinkMode} */
const INVALID_LINK_SILENT = 1,
INVALID_LINK_WARNING = 2,
INVALID_LINK_EXCEPTION = 3;
const INVALID_LINK_SILENT = 0,
INVALID_LINK_WARNING = 1,
INVALID_LINK_EXCEPTION = 2,
INVALID_LINK_TEXTUAL = 4;

/** @internal special parameter key */
const SIGNAL_KEY = 'do',
Expand Down Expand Up @@ -1060,15 +1061,14 @@ public static function argsToParams($class, $method, & $args, $supplemental = ar
*/
protected function handleInvalidLink(InvalidLinkException $e)
{
if ($this->invalidLinkMode === self::INVALID_LINK_SILENT) {
return '#';

} elseif ($this->invalidLinkMode === self::INVALID_LINK_WARNING) {
return '#error: ' . $e->getMessage();

} else { // self::INVALID_LINK_EXCEPTION
if ($this->invalidLinkMode & self::INVALID_LINK_EXCEPTION) {
throw $e;
} elseif ($this->invalidLinkMode & self::INVALID_LINK_WARNING) {
trigger_error('Invalid link: ' . $e->getMessage(), E_USER_WARNING);
}
return $this->invalidLinkMode & self::INVALID_LINK_TEXTUAL
? '#error: ' . $e->getMessage()
: '#';
}


Expand Down
18 changes: 13 additions & 5 deletions src/Bridges/ApplicationDI/ApplicationExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ class ApplicationExtension extends Nette\DI\CompilerExtension
'scanDirs' => array(),
'scanComposer' => NULL,
'scanFilter' => 'Presenter',
'silentLinks' => FALSE,
);

/** @var bool */
private $debugMode;

/** @var int */
private $invalidLinkMode;


public function __construct($debugMode = FALSE, array $scanDirs = NULL)
{
Expand All @@ -47,6 +51,10 @@ public function loadConfiguration()
$container = $this->getContainerBuilder();
$container->addExcludedClasses(array('Nette\Application\UI\Control'));

$this->invalidLinkMode = $this->debugMode
? UI\Presenter::INVALID_LINK_TEXTUAL | ($config['silentLinks'] ? 0 : UI\Presenter::INVALID_LINK_WARNING)
: UI\Presenter::INVALID_LINK_WARNING;

$application = $container->addDefinition($this->prefix('application'))
->setClass('Nette\Application\Application')
->addSetup('$catchExceptions', array($config['catchExceptions']))
Expand All @@ -56,10 +64,12 @@ public function loadConfiguration()
$application->addSetup('Nette\Bridges\ApplicationTracy\RoutingPanel::initializePanel');
}

$touchToRebuild = $this->debugMode && $config['scanDirs'] ? reset($config['scanDirs']) : NULL;
$touch = $this->debugMode && $config['scanDirs'] ? reset($config['scanDirs']) : NULL; // dir added as dependency
$presenterFactory = $container->addDefinition($this->prefix('presenterFactory'))
->setClass('Nette\Application\IPresenterFactory')
->setFactory('Nette\Application\PresenterFactory', array(1 => $touchToRebuild));
->setFactory('Nette\Application\PresenterFactory', array(new Nette\DI\Statement(
'Nette\Bridges\ApplicationDI\PresenterFactoryCallback', array(1 => $this->invalidLinkMode, $touch)
)));

if ($config['mapping']) {
$presenterFactory->addSetup('setMapping', array($config['mapping']));
Expand Down Expand Up @@ -96,9 +106,7 @@ public function beforeCompile()
foreach ($all as $def) {
$def->setInject(TRUE)->setAutowired(FALSE)->addTag('nette.presenter', $def->getClass());
if (is_subclass_of($def->getClass(), 'Nette\Application\UI\Presenter')) {
$def->addSetup('$invalidLinkMode', array(
$this->debugMode ? UI\Presenter::INVALID_LINK_WARNING : UI\Presenter::INVALID_LINK_SILENT
));
$def->addSetup('$invalidLinkMode', array($this->invalidLinkMode));
}
}
}
Expand Down
62 changes: 62 additions & 0 deletions src/Bridges/ApplicationDI/PresenterFactoryCallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

/**
* This file is part of the Nette Framework (http://nette.org)
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
*/

namespace Nette\Bridges\ApplicationDI;

use Nette;


/**
* PresenterFactory callback.
* @internal
*/
class PresenterFactoryCallback
{
/** @var Nette\DI\Container */
private $container;

/** @var int */
private $invalidLinkMode;

/** @var string|NULL */
private $touchToRefresh;


public function __construct(Nette\DI\Container $container, $invalidLinkMode, $touchToRefresh)
{
$this->container = $container;
$this->invalidLinkMode = $invalidLinkMode;
$this->touchToRefresh = $touchToRefresh;
}


/**
* @return Nette\Application\IPresenter
*/
public function __invoke($class)
{
$services = array_keys($this->container->findByTag('nette.presenter'), $class);
if (count($services) > 1) {
throw new Nette\Application\InvalidPresenterException("Multiple services of type $class found: " . implode(', ', $services) . '.');

} elseif (!$services) {
if ($this->touchToRefresh) {
touch($this->touchToRefresh);
}

$presenter = $this->container->createInstance($class);
$this->container->callInjects($presenter);
if ($presenter instanceof Nette\Application\UI\Presenter && $presenter->invalidLinkMode === NULL) {
$presenter->invalidLinkMode = $this->invalidLinkMode;
}
return $presenter;
}

return $this->container->createService($services[0]);
}

}
110 changes: 110 additions & 0 deletions tests/Application.DI/ApplicationExtension.invalidLink.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

/**
* Test: ApplicationExtension
*/

use Nette\DI,
Nette\Bridges\ApplicationDI\ApplicationExtension,
Nette\Application\UI\Presenter,
Tester\Assert;


require __DIR__ . '/../bootstrap.php';
require __DIR__ . '/files/MyPresenter.php';


function createCompiler($config)
{
$compiler = new DI\Compiler;
$compiler->loadConfig(Tester\FileMock::create($config, 'neon'));
$builder = $compiler->getContainerBuilder();
$builder->addDefinition('myRouter')->setClass('Nette\Application\Routers\SimpleRouter');
$builder->addDefinition('myHttpRequest')->setFactory('Nette\Http\Request', array(new DI\Statement('Nette\Http\UrlScript')));
$builder->addDefinition('myHttpResponse')->setClass('Nette\Http\Response');
return $compiler;
}


test(function() {
$compiler = createCompiler('
application:
debugger: no
silentLinks: yes
services:
presenter: Presenter1
');
$compiler->addExtension('application', new ApplicationExtension(TRUE));
$code = $compiler->compile(NULL, 'Container4');
eval($code);

$container = new Container4;
Assert::same(
Presenter::INVALID_LINK_TEXTUAL,
$container->getService('presenter')->invalidLinkMode
);
});


test(function() {
$compiler = createCompiler('
application:
debugger: no
silentLinks: no
services:
presenter: Presenter1
');
$compiler->addExtension('application', new ApplicationExtension(TRUE));
$code = $compiler->compile(NULL, 'Container5');
eval($code);

$container = new Container5;
Assert::same(
Presenter::INVALID_LINK_WARNING | Presenter::INVALID_LINK_TEXTUAL,
$container->getService('presenter')->invalidLinkMode
);
});


test(function() {
$compiler = createCompiler('
application:
debugger: no
silentLinks: yes
services:
presenter: Presenter1
');
$compiler->addExtension('application', new ApplicationExtension(FALSE));
$code = $compiler->compile(NULL, 'Container6');
eval($code);

$container = new Container6;
Assert::same(
Presenter::INVALID_LINK_WARNING,
$container->getService('presenter')->invalidLinkMode
);
});


test(function() {
$compiler = createCompiler('
application:
debugger: no
silentLinks: no
services:
presenter: Presenter1
');
$compiler->addExtension('application', new ApplicationExtension(FALSE));
$code = $compiler->compile(NULL, 'Container7');
eval($code);

$container = new Container7;
Assert::same(
Presenter::INVALID_LINK_WARNING,
$container->getService('presenter')->invalidLinkMode
);
});
2 changes: 1 addition & 1 deletion tests/Application.Routers/LinkGenerator.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace {
Tester\Assert;


$pf = new PresenterFactory(new Nette\DI\Container);
$pf = new PresenterFactory;


test(function() use ($pf) {
Expand Down
18 changes: 18 additions & 0 deletions tests/Application/Presenter.link().phpt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class TestPresenter extends Application\UI\Presenter
{
parent::startup();
$this['mycontrol'] = new TestControl;
$this->invalidLinkMode = self::INVALID_LINK_TEXTUAL;

// Presenter & action link
Assert::same( '/index.php?action=product&presenter=Test', $this->link('product', array('var1' => $this->var1)) );
Expand Down Expand Up @@ -133,6 +134,23 @@ class TestPresenter extends Application\UI\Presenter
$this['mycontrol']->order = 1;
Assert::same( "#error: Invalid value for persistent parameter 'order' in 'mycontrol', expected array.", $this['mycontrol']->link('click') );
$this['mycontrol']->order = NULL;

// silent invalid link mode
$this->invalidLinkMode = self::INVALID_LINK_SILENT;
Assert::same('#', $this->link('product', array('var1' => null, 'ok' => 'a')));

// warning invalid link mode
$this->invalidLinkMode = self::INVALID_LINK_WARNING;
$me = $this;
Assert::error(function() use ($me) {
Assert::same('#', $me->link('product', array('var1' => null, 'ok' => 'a')));
}, E_USER_WARNING, "Invalid link: Invalid value for persistent parameter 'ok' in 'Test', expected boolean.");

// exception invalid link mode
$this->invalidLinkMode = self::INVALID_LINK_EXCEPTION;
Assert::exception(function() use ($me) {
$me->link('product', array('var1' => null, 'ok' => 'a'));
}, 'Nette\Application\UI\InvalidLinkException', "Invalid value for persistent parameter 'ok' in 'Test', expected boolean.");
}


Expand Down
4 changes: 2 additions & 2 deletions tests/Application/PresenterFactory.formatPresenterClass.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require __DIR__ . '/../bootstrap.php';


test(function() {
$factory = new PresenterFactory(new Nette\DI\Container);
$factory = new PresenterFactory;

$factory->setMapping(array(
'Foo2' => 'App2\*\*Presenter',
Expand All @@ -35,7 +35,7 @@ test(function() {


test(function() {
$factory = new PresenterFactory(new Nette\DI\Container);
$factory = new PresenterFactory;

$factory->setMapping(array(
'Foo2' => 'App2\*Presenter',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use Nette\Application\PresenterFactory,
require __DIR__ . '/../bootstrap.php';


$factory = new PresenterFactory(new Nette\DI\Container);
$factory = new PresenterFactory;

test(function() use ($factory) {
$factory->setMapping(array(
Expand Down

0 comments on commit 3c63c03

Please sign in to comment.