From 61491fd448fb3d174557eb1afca40712fac03e5c Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 14 Jul 2016 16:55:29 +0200 Subject: [PATCH 1/6] travis: added PHP 7.1 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index e363a0d4d..e8b1d534f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: php php: - 5.6 - 7.0 + - 7.1 env: - PHP_BIN=php @@ -14,6 +15,9 @@ matrix: - php: 7.0 env: coverage="--coverage ./coverage.xml --coverage-src ./src" PHP_BIN=phpdbg + allow_failures: + - php: 7.1 + script: - vendor/bin/tester -p $PHP_BIN tests -s $coverage - php temp/code-checker/src/code-checker.php --short-arrays From 03b8b34a0518b7adc09883564dccaacde738af22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Havl=C3=AD=C4=8Dek?= Date: Thu, 21 Jul 2016 17:26:57 +0200 Subject: [PATCH 2/6] ComponentReflection::parseAnnotations: fixed regexp quoting --- src/Application/UI/ComponentReflection.php | 2 +- tests/UI/ComponentReflection.parseAnnotation.phpt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Application/UI/ComponentReflection.php b/src/Application/UI/ComponentReflection.php index 3471e798b..4d2a71e67 100644 --- a/src/Application/UI/ComponentReflection.php +++ b/src/Application/UI/ComponentReflection.php @@ -195,7 +195,7 @@ public static function convertType(& $val, $type, $isClass = FALSE) */ public static function parseAnnotation(\Reflector $ref, $name) { - if (!preg_match_all("#[\\s*]@$name(?:\(\\s*([^)]*)\\s*\))?#", $ref->getDocComment(), $m)) { + if (!preg_match_all('#[\\s*]@' . preg_quote($name, '#') . '(?:\(\\s*([^)]*)\\s*\))?#', $ref->getDocComment(), $m)) { return FALSE; } static $tokens = ['true' => TRUE, 'false' => FALSE, 'null' => NULL]; diff --git a/tests/UI/ComponentReflection.parseAnnotation.phpt b/tests/UI/ComponentReflection.parseAnnotation.phpt index 865efe07f..1e9e2f929 100644 --- a/tests/UI/ComponentReflection.parseAnnotation.phpt +++ b/tests/UI/ComponentReflection.parseAnnotation.phpt @@ -22,6 +22,7 @@ require __DIR__ . '/../bootstrap.php'; * @author *@renderable * @secured(role = "admin", level = 2) + * @Secured\User(loggedIn) */ class TestClass {} @@ -32,4 +33,5 @@ Assert::same(['value ="Johno\'s addendum"', 'mode=True', TRUE, TRUE], Reflection Assert::same(['item 1'], Reflection::parseAnnotation($rc, 'components')); Assert::same([TRUE, FALSE, NULL], Reflection::parseAnnotation($rc, 'persistent')); Assert::same([TRUE], Reflection::parseAnnotation($rc, 'renderable')); +Assert::same(['loggedIn'], Reflection::parseAnnotation($rc, 'Secured\User')); Assert::false(Reflection::parseAnnotation($rc, 'missing')); From 98895220ab31c1ac6b8e6f4d85a9eeb4b3bf3a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Hansl=C3=ADk?= Date: Wed, 27 Jul 2016 14:26:24 +0200 Subject: [PATCH 3/6] Presenter: flash key has to be string (fix for "Array to string conversion" notice) (#147) --- src/Application/UI/Presenter.php | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 1eb1b56ea..a7d04e150 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -945,7 +945,7 @@ protected function createRequest($component, $destination, array $args, $mode) $current = $current && $args[self::SIGNAL_KEY] === $this->getParameter(self::SIGNAL_KEY); } if (($mode === 'redirect' || $mode === 'forward') && $this->hasFlashSession()) { - $args[self::FLASH_KEY] = $this->getParameter(self::FLASH_KEY); + $args[self::FLASH_KEY] = $this->getFlashKey(); } $this->lastCreatedRequest = new Application\Request( @@ -1103,7 +1103,7 @@ public function restoreRequest($key) unset($session[$key]); $request->setFlag(Application\Request::RESTORED, TRUE); $params = $request->getParameters(); - $params[self::FLASH_KEY] = $this->getParameter(self::FLASH_KEY); + $params[self::FLASH_KEY] = $this->getFlashKey(); $request->setParameters($params); $this->sendResponse(new Responses\ForwardResponse($request)); } @@ -1282,14 +1282,27 @@ public function popGlobalParameters($id) /********************* flash session ****************d*g**/ + /** + * @return string|NULL + */ + private function getFlashKey() + { + $flashKey = $this->getParameter(self::FLASH_KEY); + return is_string($flashKey) && $flashKey !== '' + ? $flashKey + : NULL; + } + + /** * Checks if a flash session namespace exists. * @return bool */ public function hasFlashSession() { - return !empty($this->params[self::FLASH_KEY]) - && $this->getSession()->hasSection('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]); + $flashKey = $this->getFlashKey(); + return $flashKey !== NULL + && $this->getSession()->hasSection('Nette.Application.Flash/' . $flashKey); } @@ -1299,10 +1312,11 @@ public function hasFlashSession() */ public function getFlashSession() { - if (empty($this->params[self::FLASH_KEY])) { - $this->params[self::FLASH_KEY] = Nette\Utils\Random::generate(4); + $flashKey = $this->getFlashKey(); + if ($flashKey === NULL) { + $this->params[self::FLASH_KEY] = $flashKey = Nette\Utils\Random::generate(4); } - return $this->getSession('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]); + return $this->getSession('Nette.Application.Flash/' . $flashKey); } From 86eb0ee1fc516d6e47218532b67e5d8bdb9cc420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Tvrd=C3=ADk?= Date: Wed, 27 Jul 2016 14:36:28 +0200 Subject: [PATCH 4/6] Presenter: fixed creating link with required persistent parameters (#148) --- src/Application/LinkGenerator.php | 7 ++++++- src/Application/UI/Presenter.php | 23 ++++++++++++++++------- tests/UI/Presenter.link().php7.phpt | 7 +++++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/Application/LinkGenerator.php b/src/Application/LinkGenerator.php index 8adebced3..b7ab45153 100644 --- a/src/Application/LinkGenerator.php +++ b/src/Application/LinkGenerator.php @@ -61,7 +61,12 @@ public function link($dest, array $params = []) if (method_exists($class, $method = $class::formatActionMethod($action)) || method_exists($class, $method = $class::formatRenderMethod($action)) ) { - UI\Presenter::argsToParams($class, $method, $params); + UI\Presenter::argsToParams($class, $method, $params, [], $missing); + if ($missing) { + $rp = $missing[0]; + throw new UI\InvalidLinkException("Missing parameter \${$rp->getName()} required by {$rp->getDeclaringClass()->getName()}::{$rp->getDeclaringFunction()->getName()}()"); + } + } elseif (array_key_exists(0, $params)) { throw new UI\InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method."); } diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index a7d04e150..8a2e8cb66 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -869,7 +869,7 @@ protected function createRequest($component, $destination, array $args, $mode) throw new InvalidLinkException("Unknown signal '$signal', missing handler {$reflection->getName()}::$method()"); } // convert indexed parameters to named - self::argsToParams(get_class($component), $method, $args, [], $mode === 'test'); + self::argsToParams(get_class($component), $method, $args, [], $missing); } // counterpart of IStatePersistent @@ -911,7 +911,7 @@ protected function createRequest($component, $destination, array $args, $mode) throw new InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method."); } } else { - self::argsToParams($presenterClass, $method, $args, $destination === 'this' ? $this->params : [], $mode === 'test'); + self::argsToParams($presenterClass, $method, $args, $destination === 'this' ? $this->params : [], $missing); } // counterpart of IStatePersistent @@ -936,6 +936,14 @@ protected function createRequest($component, $destination, array $args, $mode) $args += $globalState; } + if ($mode !== 'test' && !empty($missing)) { + foreach ($missing as $rp) { + if (!array_key_exists($rp->getName(), $args)) { + throw new InvalidLinkException("Missing parameter \${$rp->getName()} required by {$rp->getDeclaringClass()->getName()}::{$rp->getDeclaringFunction()->getName()}()"); + } + } + } + // ADD ACTION & SIGNAL & FLASH if ($action) { $args[self::ACTION_KEY] = $action; @@ -995,12 +1003,12 @@ protected function createRequest($component, $destination, array $args, $mode) * @param string method name * @param array arguments * @param array supplemental arguments - * @param bool prevents 'Missing parameter' exception + * @param ReflectionParameter[] missing arguments * @return void * @throws InvalidLinkException * @internal */ - public static function argsToParams($class, $method, & $args, $supplemental = [], $ignoreMissing = FALSE) + public static function argsToParams($class, $method, & $args, $supplemental = [], & $missing = []) { $i = 0; $rm = new \ReflectionMethod($class, $method); @@ -1021,10 +1029,11 @@ public static function argsToParams($class, $method, & $args, $supplemental = [] } if (!isset($args[$name])) { - if ($param->isDefaultValueAvailable() || $type === 'NULL' || $type === 'array' || $ignoreMissing) { - continue; + if (!$param->isDefaultValueAvailable() && $type !== 'NULL' && $type !== 'array') { + $missing[] = $param; + unset($args[$name]); } - throw new InvalidLinkException("Missing parameter \$$name required by $class::{$rm->getName()}()"); + continue; } if (!ComponentReflection::convertType($args[$name], $type, $isClass)) { diff --git a/tests/UI/Presenter.link().php7.phpt b/tests/UI/Presenter.link().php7.phpt index ce193d991..1d252e77b 100644 --- a/tests/UI/Presenter.link().php7.phpt +++ b/tests/UI/Presenter.link().php7.phpt @@ -100,6 +100,7 @@ class TestPresenter extends Application\UI\Presenter Assert::same('/index.php?pint=0&pbool=0&p=0&action=params&presenter=Test', $this->link('params', ['pint' => FALSE, 'pbool' => FALSE, 'p' => FALSE, 'parr' => NULL])); Assert::same("#error: Value passed to persistent parameter 'pbool' in presenter Test must be boolean, string given.", $this->link('this', ['p' => NULL, 'pbool' => 'a'])); Assert::same("#error: Value passed to persistent parameter 'p' in presenter Test must be scalar, array given.", $this->link('this', ['p' => [1], 'pbool' => FALSE])); + Assert::same('/index.php?action=persistent&presenter=Test', $this->link('persistent')); // Other presenter & action link Assert::same('/index.php?action=product&presenter=Other', $this->link('Other:product', ['p' => $this->p])); @@ -238,6 +239,12 @@ class TestPresenter extends Application\UI\Presenter { } + + public function actionPersistent(int $pint) + { + } + + public function handleSignal($x = 1, $y = 1) { } From 82330d4a374a619ca51da59db76408454c82f18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20=C4=8Cech?= Date: Thu, 28 Jul 2016 16:09:01 +0200 Subject: [PATCH 5/6] Presenter: removed static from refUrl variable (#80) --- src/Application/UI/Presenter.php | 14 +++--- tests/Application/Presenter.twoDomains.phpt | 56 +++++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 tests/Application/Presenter.twoDomains.phpt diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 8a2e8cb66..683162972 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -121,6 +121,9 @@ abstract class Presenter extends Control implements Application\IPresenter /** @var ITemplateFactory */ private $templateFactory; + /** @var Nette\Http\Url */ + private $refUrlCache; + public function __construct() { @@ -970,15 +973,14 @@ protected function createRequest($component, $destination, array $args, $mode) } // CONSTRUCT URL - static $refUrl; - if ($refUrl === NULL) { - $refUrl = new Http\Url($this->httpRequest->getUrl()); - $refUrl->setPath($this->httpRequest->getUrl()->getScriptPath()); + if ($this->refUrlCache === NULL) { + $this->refUrlCache = new Http\Url($this->httpRequest->getUrl()); + $this->refUrlCache->setPath($this->httpRequest->getUrl()->getScriptPath()); } if (!$this->router) { throw new Nette\InvalidStateException('Unable to generate URL, service Router has not been set.'); } - $url = $this->router->constructUrl($this->lastCreatedRequest, $refUrl); + $url = $this->router->constructUrl($this->lastCreatedRequest, $this->refUrlCache); if ($url === NULL) { unset($args[self::ACTION_KEY]); $params = urldecode(http_build_query($args, NULL, ', ')); @@ -987,7 +989,7 @@ protected function createRequest($component, $destination, array $args, $mode) // make URL relative if possible if ($mode === 'link' && $scheme === FALSE && !$this->absoluteUrls) { - $hostUrl = $refUrl->getHostUrl() . '/'; + $hostUrl = $this->refUrlCache->getHostUrl() . '/'; if (strncmp($url, $hostUrl, strlen($hostUrl)) === 0) { $url = substr($url, strlen($hostUrl) - 1); } diff --git a/tests/Application/Presenter.twoDomains.phpt b/tests/Application/Presenter.twoDomains.phpt new file mode 100644 index 000000000..badb81b53 --- /dev/null +++ b/tests/Application/Presenter.twoDomains.phpt @@ -0,0 +1,56 @@ +setScriptPath('/index.php'); + + $presenter = new TestPresenter; + $presenter->injectPrimary( + NULL, + new MockPresenterFactory, + new Application\Routers\SimpleRouter, + new Http\Request($url), + new Http\Response + ); + + $request = new Application\Request('Test', Http\Request::GET, []); + $presenter->run($request); + + Assert::same( 'http://' . $domain . '/index.php?action=default&presenter=Test', $presenter->link('//this') ); +} + +testLink('first.localhost'); +testLink('second.localhost'); From d47e06c90589184f8846fe7483a885b34168c370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mat=C4=9Bjka?= Date: Sat, 30 Jul 2016 18:03:49 +0200 Subject: [PATCH 6/6] SnippetBridge: added setSnippetMode; added snippet test (#150) --- composer.json | 2 +- .../ApplicationLatte/SnippetBridge.php | 6 +++ .../UIMacros.renderSnippets4.phpt | 49 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/Bridges.Latte/UIMacros.renderSnippets4.phpt diff --git a/composer.json b/composer.json index 8a89de639..0175c0e39 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "nette/forms": "~2.4", "nette/robot-loader": "~2.4", "nette/security": "~2.4", - "latte/latte": "~2.4", + "latte/latte": "^2.4.1", "tracy/tracy": "^2.4" }, "conflict": { diff --git a/src/Bridges/ApplicationLatte/SnippetBridge.php b/src/Bridges/ApplicationLatte/SnippetBridge.php index 45f4b4406..86f5be6d0 100644 --- a/src/Bridges/ApplicationLatte/SnippetBridge.php +++ b/src/Bridges/ApplicationLatte/SnippetBridge.php @@ -39,6 +39,12 @@ public function isSnippetMode() } + public function setSnippetMode($snippetMode) + { + $this->control->snippetMode = $snippetMode; + } + + public function needsRedraw($name) { return $this->control->isControlInvalid($name); diff --git a/tests/Bridges.Latte/UIMacros.renderSnippets4.phpt b/tests/Bridges.Latte/UIMacros.renderSnippets4.phpt new file mode 100644 index 000000000..9388489d7 --- /dev/null +++ b/tests/Bridges.Latte/UIMacros.renderSnippets4.phpt @@ -0,0 +1,49 @@ +setLoader(new Latte\Loaders\StringLoader); + UIMacros::install($latte->getCompiler()); + $latte->addProvider('uiControl', $this); + $latte->addProvider('snippetBridge', new SnippetBridge($this)); + $latte->render('{snippet foo}{php $presenter->renderFoo()}{/snippet}', ['presenter' => $this]); + } + + public function renderFoo() + { + $latte = new Latte\Engine; + $latte->setLoader(new Latte\Loaders\StringLoader); + UIMacros::install($latte->getCompiler()); + $latte->addProvider('uiControl', $this); + $latte->addProvider('snippetBridge', new SnippetBridge($this)); + $latte->render('Hello'); + } +} + + +$presenter = new TestPresenter; +$presenter->snippetMode = TRUE; +$presenter->redrawControl('foo'); +$presenter->render(); +Assert::same([ + 'snippets' => [ + 'snippet--foo' => 'Hello', + ], +], (array) $presenter->payload);