diff --git a/Nette/Application/MicroPresenter.php b/Nette/Application/MicroPresenter.php index 8c99574c05..73af2c1568 100644 --- a/Nette/Application/MicroPresenter.php +++ b/Nette/Application/MicroPresenter.php @@ -75,8 +75,8 @@ public function run(Application\Request $request) return; } $params['presenter'] = $this; - $method = callback($params['callback'])->toReflection(); - $response = $method->invokeArgs(Application\UI\PresenterComponentReflection::combineArgs($method, $params)); + $callback = callback($params['callback']); + $response = $callback->invokeArgs(Application\UI\PresenterComponentReflection::combineArgs($callback->toReflection(), $params)); if (is_string($response)) { $response = array($response, array()); diff --git a/Nette/Application/PresenterFactory.php b/Nette/Application/PresenterFactory.php index 3fe69d547c..09ba921fb9 100644 --- a/Nette/Application/PresenterFactory.php +++ b/Nette/Application/PresenterFactory.php @@ -32,17 +32,17 @@ class PresenterFactory implements IPresenterFactory private $cache = array(); /** @var Nette\DI\Container */ - private $context; + private $container; /** * @param string */ - public function __construct($baseDir, Nette\DI\Container $context) + public function __construct($baseDir, Nette\DI\Container $container) { $this->baseDir = $baseDir; - $this->context = $context; + $this->container = $container; } @@ -54,9 +54,9 @@ public function __construct($baseDir, Nette\DI\Container $context) */ public function createPresenter($name) { - $presenter = $this->context->createInstance($this->getPresenterClass($name)); + $presenter = $this->container->createInstance($this->getPresenterClass($name)); if (method_exists($presenter, 'setContext')) { - $this->context->callMethod(array($presenter, 'setContext')); + $this->container->callMethod(array($presenter, 'setContext')); } return $presenter; } diff --git a/Nette/Application/Routers/Route.php b/Nette/Application/Routers/Route.php index 4cb81c04f9..1c5c581645 100644 --- a/Nette/Application/Routers/Route.php +++ b/Nette/Application/Routers/Route.php @@ -62,7 +62,7 @@ class Route extends Nette\Object implements Application\IRouter '#' => array( // default style for path parameters self::PATTERN => '[^/]+', self::FILTER_IN => 'rawurldecode', - self::FILTER_OUT => 'rawurlencode', + self::FILTER_OUT => array(__CLASS__, 'param2path'), ), '?#' => array( // default style for query parameters ), @@ -766,6 +766,18 @@ private static function path2presenter($s) + /** + * Url encode. + * @param string + * @return string + */ + private static function param2path($s) + { + return str_replace('%2F', '/', rawurlencode($s)); + } + + + /********************* Route::$styles manipulator ****************d*g**/ diff --git a/Nette/Application/UI/Form.php b/Nette/Application/UI/Form.php index 9d74ed389a..6db389a116 100644 --- a/Nette/Application/UI/Form.php +++ b/Nette/Application/UI/Form.php @@ -75,7 +75,9 @@ protected function attached($presenter) // fill-in the form with HTTP data if ($this->isSubmitted()) { foreach ($this->getControls() as $control) { - $control->loadHttpData(); + if (!$control->isDisabled()) { + $control->loadHttpData(); + } } } } diff --git a/Nette/Application/UI/Presenter.php b/Nette/Application/UI/Presenter.php index 01d625a64d..37a778d2ac 100644 --- a/Nette/Application/UI/Presenter.php +++ b/Nette/Application/UI/Presenter.php @@ -108,7 +108,7 @@ abstract class Presenter extends Control implements Application\IPresenter /** @var array */ private $lastCreatedRequestFlag; - /** @var Nette\DI\Container */ + /** @var \SystemContainer|Nette\DI\Container */ private $context; @@ -508,7 +508,8 @@ public function formatLayoutTemplateFiles() $name = $this->getName(); $presenter = substr($name, strrpos(':' . $name, ':')); $layout = $this->layout ? $this->layout : 'layout'; - $dir = dirname(dirname($this->getReflection()->getFileName())); + $dir = dirname($this->getReflection()->getFileName()); + $dir = is_dir("$dir/templates") ? $dir : dirname($dir); $list = array( "$dir/templates/$presenter/@$layout.latte", "$dir/templates/$presenter.@$layout.latte", @@ -533,7 +534,8 @@ public function formatTemplateFiles() { $name = $this->getName(); $presenter = substr($name, strrpos(':' . $name, ':')); - $dir = dirname(dirname($this->getReflection()->getFileName())); + $dir = dirname($this->getReflection()->getFileName()); + $dir = is_dir("$dir/templates") ? $dir : dirname($dir); return array( "$dir/templates/$presenter/$this->view.latte", "$dir/templates/$presenter.$this->view.latte", @@ -967,7 +969,7 @@ final protected function createRequest($component, $destination, array $args, $m if ($current && $args) { $tmp = $globalState + $this->params; foreach ($args as $key => $val) { - if ((string) $val !== (isset($tmp[$key]) ? (string) $tmp[$key] : '')) { + if (http_build_query(array($val)) !== (isset($tmp[$key]) ? http_build_query(array($tmp[$key])) : '')) { $current = FALSE; break; } @@ -1050,33 +1052,17 @@ private static function argsToParams($class, $method, & $args, $supplemental = a continue; } + if ($args[$name] === NULL) { + continue; + } $def = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL; - $val = $args[$name]; - if ($val === NULL) { - continue; - } elseif ($param->isArray() || is_array($def)) { - if (!is_array($val)) { - throw new InvalidLinkException("Invalid value for parameter '$name', expected array."); - } - } elseif ($param->getClass() || is_object($val)) { - // ignore - } elseif (!is_scalar($val)) { - throw new InvalidLinkException("Invalid value for parameter '$name', expected scalar."); - - } elseif ($def === NULL) { - if ((string) $val === '') { - $args[$name] = NULL; // value transmit is unnecessary - } - continue; - } else { - settype($args[$name], gettype($def)); - if ((string) $args[$name] !== (string) $val) { - throw new InvalidLinkException("Invalid value for parameter '$name', expected ".gettype($def)."."); - } + $type = $param->isArray() ? 'array' : gettype($def); + if (!PresenterComponentReflection::convertType($args[$name], $type)) { + throw new InvalidLinkException("Invalid value for parameter '$name' in method $class::$method(), expected " . ($type === 'NULL' ? 'scalar' : $type) . "."); } - if ($args[$name] === $def) { + if ($args[$name] === $def || ($def === NULL && is_scalar($args[$name]) && (string) $args[$name] === '')) { $args[$name] = NULL; // value transmit is unnecessary } } @@ -1193,8 +1179,8 @@ private function getGlobalState($forClass = NULL) if ($sinces === NULL) { $sinces = array(); - foreach ($this->getReflection()->getPersistentParams() as $nm => $meta) { - $sinces[$nm] = $meta['since']; + foreach ($this->getReflection()->getPersistentParams() as $name => $meta) { + $sinces[$name] = $meta['since']; } } diff --git a/Nette/Application/UI/PresenterComponent.php b/Nette/Application/UI/PresenterComponent.php index 378d26a57d..1cd6f3cc57 100644 --- a/Nette/Application/UI/PresenterComponent.php +++ b/Nette/Application/UI/PresenterComponent.php @@ -137,18 +137,16 @@ public function checkRequirements($element) */ public function loadState(array $params) { - foreach ($this->getReflection()->getPersistentParams() as $nm => $meta) { - if (isset($params[$nm])) { // ignore NULL values - if (isset($meta['def'])) { - if (is_array($params[$nm]) && !is_array($meta['def'])) { - $params[$nm] = $meta['def']; // prevents array to scalar conversion - } else { - settype($params[$nm], gettype($meta['def'])); - } + $reflection = $this->getReflection(); + foreach ($reflection->getPersistentParams() as $name => $meta) { + if (isset($params[$name])) { // NULLs are ignored + $type = gettype($meta['def'] === NULL ? $params[$name] : $meta['def']); // compatible with 2.0.x + if (!$reflection->convertType($params[$name], $type)) { + throw new Nette\Application\BadRequestException("Invalid value for persistent parameter '$name' in '{$this->getName()}', expected " . ($type === 'NULL' ? 'scalar' : $type) . "."); } - $this->$nm = & $params[$nm]; + $this->$name = & $params[$name]; } else { - $params[$nm] = & $this->$nm; + $params[$name] = & $this->$name; } } $this->params = $params; @@ -165,37 +163,28 @@ public function loadState(array $params) public function saveState(array & $params, $reflection = NULL) { $reflection = $reflection === NULL ? $this->getReflection() : $reflection; - foreach ($reflection->getPersistentParams() as $nm => $meta) { + foreach ($reflection->getPersistentParams() as $name => $meta) { - if (isset($params[$nm])) { - $val = $params[$nm]; // injected value + if (isset($params[$name])) { + // injected value - } elseif (array_key_exists($nm, $params)) { // $params[$nm] === NULL - continue; // means skip + } elseif (array_key_exists($name, $params)) { // NULLs are skipped + continue; } elseif (!isset($meta['since']) || $this instanceof $meta['since']) { - $val = $this->$nm; // object property value + $params[$name] = $this->$name; // object property value } else { continue; // ignored parameter } - if (is_object($val)) { - $class = get_class($this); - throw new Nette\InvalidStateException("Persistent parameter must be scalar or array, $class::\$$nm is " . gettype($val)); + $type = gettype($meta['def'] === NULL ? $params[$name] : $meta['def']); // compatible with 2.0.x + if (!PresenterComponentReflection::convertType($params[$name], $type)) { + throw new InvalidLinkException("Invalid value for persistent parameter '$name' in '{$this->getName()}', expected " . ($type === 'NULL' ? 'scalar' : $type) . "."); + } - } else { - if (isset($meta['def'])) { - settype($val, gettype($meta['def'])); - if ($val === $meta['def']) { - $val = NULL; - } - } else { - if ((string) $val === '') { - $val = NULL; - } - } - $params[$nm] = $val; + if ($params[$name] === $meta['def'] || ($meta['def'] === NULL && is_scalar($params[$name]) && (string) $params[$name] === '')) { + $params[$name] = NULL; // value transmit is unnecessary } } } @@ -241,13 +230,7 @@ final public function getParameterId($name) function getParam($name = NULL, $default = NULL) { //trigger_error(__METHOD__ . '() is deprecated; use getParameter() instead.', E_USER_WARNING); - if (func_num_args() === 0) { - return $this->params; - } elseif (isset($this->params[$name])) { - return $this->params[$name]; - } else { - return $default; - } + return func_num_args() ? $this->getParameter($name, $default) : $this->getParameter(); } diff --git a/Nette/Application/UI/PresenterComponentReflection.php b/Nette/Application/UI/PresenterComponentReflection.php index df45db1ba8..ec08791422 100644 --- a/Nette/Application/UI/PresenterComponentReflection.php +++ b/Nette/Application/UI/PresenterComponentReflection.php @@ -48,9 +48,8 @@ public function getPersistentParams($class = NULL) } $params = array(); if (is_subclass_of($class, 'Nette\Application\UI\PresenterComponent')) { - // $class::getPersistentParams() in PHP 5.3 $defaults = get_class_vars($class); - foreach (call_user_func(array($class, 'getPersistentParams'), $class) as $name => $meta) { + foreach (/**/$class::getPersistentParams()/**//*5.2*call_user_func(array($class, 'getPersistentParams'), $class)*/ as $name => $meta) { if (is_string($meta)) { $name = $meta; } @@ -86,8 +85,7 @@ public function getPersistentComponents($class = NULL) } $components = array(); if (is_subclass_of($class, 'Nette\Application\UI\Presenter')) { - // $class::getPersistentComponents() in PHP 5.3 - foreach (call_user_func(array($class, 'getPersistentComponents'), $class) as $name => $meta) { + foreach (/**/$class::getPersistentComponents()/**//*5.2*call_user_func(array($class, 'getPersistentComponents'), $class)*/ as $name => $meta) { if (is_string($meta)) { $name = $meta; } @@ -130,37 +128,47 @@ public static function combineArgs(\ReflectionFunctionAbstract $method, $args) $i = 0; foreach ($method->getParameters() as $param) { $name = $param->getName(); - $def = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL; - - if (!isset($args[$name])) { // NULL treats as none value - if ($param->isArray() && !$param->allowsNull()) { - $def = (array) $def; + if (isset($args[$name])) { // NULLs are ignored + $res[$i++] = $args[$name]; + $type = $param->isArray() ? 'array' : ($param->isDefaultValueAvailable() ? gettype($param->getDefaultValue()) : 'NULL'); + if (!self::convertType($res[$i-1], $type)) { + $mName = $method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' . $method->getName() : $method->getName(); + throw new BadRequestException("Invalid value for parameter '$name' in method $mName(), expected " . ($type === 'NULL' ? 'scalar' : $type) . "."); } - $res[$i++] = $def; - } else { - $val = $args[$name]; - if ($param->isArray() || is_array($def)) { - if (!is_array($val)) { - throw new BadRequestException("Invalid value for parameter '$name', expected array."); - } - } elseif ($param->getClass() || is_object($val)) { - // ignore - } else { - if (!is_scalar($val)) { - throw new BadRequestException("Invalid value for parameter '$name', expected scalar."); - } - if ($def !== NULL) { - settype($val, gettype($def)); - if (($val === FALSE ? '0' : (string) $val) !== (string) $args[$name]) { - throw new BadRequestException("Invalid value for parameter '$name', expected ".gettype($def)."."); - } - } - } - $res[$i++] = $val; + $res[$i++] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : ($param->isArray() ? array() : NULL); } } return $res; } + + + /** + * Non data-loss type conversion. + * @param mixed + * @param string + * @return bool + */ + public static function convertType(& $val, $type) + { + if ($val === NULL || is_object($val)) { + // ignore + } elseif ($type === 'array') { + if (!is_array($val)) { + return FALSE; + } + } elseif (!is_scalar($val)) { + return FALSE; + + } elseif ($type !== 'NULL') { + $old = $val = ($val === FALSE ? '0' : (string) $val); + settype($val, $type); + if ($old !== ($val === FALSE ? '0' : (string) $val)) { + return FALSE; // data-loss occurs + } + } + return TRUE; + } + } diff --git a/Nette/ComponentModel/Container.php b/Nette/ComponentModel/Container.php index cc961e5c5e..343b396c71 100644 --- a/Nette/ComponentModel/Container.php +++ b/Nette/ComponentModel/Container.php @@ -16,7 +16,7 @@ /** - * ComponentContainer is default implementation of IComponentContainer. + * ComponentContainer is default implementation of IContainer. * * @author David Grudl * @@ -32,12 +32,12 @@ class Container extends Component implements IContainer - /********************* interface IComponentContainer ****************d*g**/ + /********************* interface IContainer ****************d*g**/ /** - * Adds the specified component to the IComponentContainer. + * Adds the specified component to the IContainer. * @param IComponent * @param string * @param string @@ -101,7 +101,7 @@ public function addComponent(IComponent $component, $name, $insertBefore = NULL) /** - * Removes a component from the IComponentContainer. + * Removes a component from the IContainer. * @param IComponent * @return void */ diff --git a/Nette/ComponentModel/IContainer.php b/Nette/ComponentModel/IContainer.php index 5ab5ab3b13..99fa31e46a 100644 --- a/Nette/ComponentModel/IContainer.php +++ b/Nette/ComponentModel/IContainer.php @@ -24,7 +24,7 @@ interface IContainer extends IComponent { /** - * Adds the specified component to the IComponentContainer. + * Adds the specified component to the IContainer. * @param IComponent * @param string * @return void @@ -32,7 +32,7 @@ interface IContainer extends IComponent function addComponent(IComponent $component, $name); /** - * Removes a component from the IComponentContainer. + * Removes a component from the IContainer. * @param IComponent * @return void */ diff --git a/Nette/Config/Compiler.php b/Nette/Config/Compiler.php index 79c9cf0388..cd3c63e272 100644 --- a/Nette/Config/Compiler.php +++ b/Nette/Config/Compiler.php @@ -113,14 +113,14 @@ public function processParameters() public function processExtensions() { + foreach ($this->extensions as $name => $extension) { + $extension->loadConfiguration(); + } + if ($extra = array_diff_key($this->config, self::$reserved, $this->extensions)) { $extra = implode("', '", array_keys($extra)); throw new Nette\InvalidStateException("Found sections '$extra' in configuration, but corresponding extensions are missing."); } - - foreach ($this->extensions as $name => $extension) { - $extension->loadConfiguration(); - } } @@ -156,6 +156,7 @@ public function generateCode($className, $parentName) { foreach ($this->extensions as $extension) { $extension->beforeCompile(); + $this->container->addDependency(Nette\Reflection\ClassType::from($extension)->getFileName()); } $classes[] = $class = $this->container->generateClass($parentName); @@ -220,7 +221,7 @@ public static function parseServices(Nette\DI\ContainerBuilder $container, array $definition = $container->addDefinition($name); if ($parent !== Helpers::OVERWRITE) { foreach ($container->getDefinition($parent) as $k => $v) { - $definition->$k = $v; + $definition->$k = unserialize(serialize($v)); // deep clone } } } elseif ($container->hasDefinition($name)) { diff --git a/Nette/Config/Configurator.php b/Nette/Config/Configurator.php index 2e3ae26be3..bf7272827e 100644 --- a/Nette/Config/Configurator.php +++ b/Nette/Config/Configurator.php @@ -187,7 +187,7 @@ public function createContainer() if (!$cached) { $code = $this->buildContainer($dependencies); $cache->save($cacheKey, $code, array( - Cache::FILES => $this->parameters['productionMode'] ? NULL : $dependencies, + Cache::FILES => $dependencies, )); $cached = $cache->load($cacheKey); } @@ -239,7 +239,7 @@ protected function buildContainer(& $dependencies = NULL) $this->parameters['container']['class'], $config['parameters']['container']['parent'] ); - $dependencies = array_merge($loader->getDependencies(), $compiler->getContainerBuilder()->getDependencies()); + $dependencies = array_merge($loader->getDependencies(), $this->isDebugMode() ? $compiler->getContainerBuilder()->getDependencies() : array()); return $code; } @@ -307,9 +307,11 @@ protected function getCacheDirectory() */ public static function detectDebugMode($list = NULL) { - $list = is_string($list) ? preg_split('#[,\s]+#', $list) : $list; - $list[] = '127.0.0.1'; - $list[] = '::1'; + $list = is_string($list) ? preg_split('#[,\s]+#', $list) : (array) $list; + if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $list[] = '127.0.0.1'; + $list[] = '::1'; + } return in_array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'), $list, TRUE); } diff --git a/Nette/Config/Extensions/NetteExtension.php b/Nette/Config/Extensions/NetteExtension.php index c3f63931c1..d26a5fc9d9 100644 --- a/Nette/Config/Extensions/NetteExtension.php +++ b/Nette/Config/Extensions/NetteExtension.php @@ -200,7 +200,6 @@ public function loadConfiguration() $container->addDefinition($this->prefix('mailer')) ->setClass('Nette\Mail\SendmailMailer'); } else { - Validators::assertField($config, 'mailer', 'array'); $container->addDefinition($this->prefix('mailer')) ->setClass('Nette\Mail\SmtpMailer', array($config['mailer'])); } @@ -237,6 +236,10 @@ public function loadConfiguration() $container->addDefinition($this->prefix('database')) ->setClass('Nette\DI\NestedAccessor', array('@container', $this->prefix('database'))); + if (isset($config['database']['dsn'])) { + $config['database'] = array('default' => $config['database']); + } + $autowired = TRUE; foreach ((array) $config['database'] as $name => $info) { if (!is_array($info)) { diff --git a/Nette/DI/Container.php b/Nette/DI/Container.php index 3a20b5344e..0796ce8287 100644 --- a/Nette/DI/Container.php +++ b/Nette/DI/Container.php @@ -258,13 +258,13 @@ public function createInstance($class, array $args = array()) { $rc = Nette\Reflection\ClassType::from($class); if (!$rc->isInstantiable()) { - throw new Nette\InvalidArgumentException("Class $class is not instantiable."); + throw new ServiceCreationException("Class $class is not instantiable."); } elseif ($constructor = $rc->getConstructor()) { return $rc->newInstanceArgs(Helpers::autowireArguments($constructor, $args, $this)); } elseif ($args) { - throw new Nette\InvalidArgumentException("Unable to pass arguments, class $class has no constructor."); + throw new ServiceCreationException("Unable to pass arguments, class $class has no constructor."); } return new $class; } diff --git a/Nette/DI/ContainerBuilder.php b/Nette/DI/ContainerBuilder.php index 18ecb5eebf..cc005863ac 100644 --- a/Nette/DI/ContainerBuilder.php +++ b/Nette/DI/ContainerBuilder.php @@ -509,7 +509,7 @@ public function formatPhp($statement, $args, $self = NULL) } elseif ($service = $that->getServiceName($val, $self)) { $val = $service === $self ? '$service' : $that->formatStatement(new Statement($val)); - $val = new PhpLiteral($val, $self); + $val = new PhpLiteral($val); } }); return PhpHelpers::formatArgs($statement, $args); diff --git a/Nette/DI/Helpers.php b/Nette/DI/Helpers.php index 680fb3180a..b53af78c5e 100644 --- a/Nette/DI/Helpers.php +++ b/Nette/DI/Helpers.php @@ -119,13 +119,13 @@ public static function autowireArguments(\ReflectionFunctionAbstract $method, ar unset($arguments[$parameter->getName()]); $optCount = 0; - } elseif ($class = $parameter->getClassName()) { // has object typehint + } elseif ($class = $parameter->getClassName()) { // has object type hint $res[$num] = $container->getByType($class, FALSE); if ($res[$num] === NULL) { if ($parameter->allowsNull()) { $optCount++; } else { - throw new Nette\InvalidArgumentException("No service of type {$class} found"); + throw new ServiceCreationException("No service of type {$class} found. Make sure the type hint in $method is written correctly and service of this type is registered."); } } else { if ($container instanceof ContainerBuilder) { @@ -140,7 +140,7 @@ public static function autowireArguments(\ReflectionFunctionAbstract $method, ar $optCount++; } else { - throw new Nette\InvalidArgumentException("$parameter is missing."); + throw new ServiceCreationException("Parameter $parameter has no type hint, so its value must be specified."); } } @@ -151,7 +151,7 @@ public static function autowireArguments(\ReflectionFunctionAbstract $method, ar $optCount = 0; } if ($arguments) { - throw new Nette\InvalidArgumentException("Unable to pass specified arguments to $method."); + throw new ServiceCreationException("Unable to pass specified arguments to $method."); } return $optCount ? array_slice($res, 0, -$optCount) : $res; diff --git a/Nette/Database/Drivers/PgSqlDriver.php b/Nette/Database/Drivers/PgSqlDriver.php index d1a98416da..b9f8644042 100644 --- a/Nette/Database/Drivers/PgSqlDriver.php +++ b/Nette/Database/Drivers/PgSqlDriver.php @@ -64,7 +64,8 @@ public function formatDateTime(\DateTime $value) */ public function formatLike($value, $pos) { - throw new Nette\NotImplementedException; + $value = strtr($value, array("'" => "''", '\\' => '\\\\', '%' => '\\\\%', '_' => '\\\\_')); + return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); } @@ -102,11 +103,20 @@ public function normalizeRow($row, $statement) */ public function getTables() { - return $this->connection->query(" - SELECT table_name as name, CAST(table_type = 'VIEW' AS INTEGER) as view - FROM information_schema.tables - WHERE table_schema = current_schema() - ")->fetchAll(); + $tables = array(); + foreach ($this->connection->query(" + SELECT + table_name AS name, + table_type = 'VIEW' AS view + FROM + information_schema.tables + WHERE + table_schema = current_schema() + ") as $row) { + $tables[] = (array) $row; + } + + return $tables; } @@ -116,33 +126,35 @@ public function getTables() */ public function getColumns($table) { - $primary = (int) $this->connection->query(" - SELECT indkey - FROM pg_class - LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid AND pg_index.indisprimary - WHERE pg_class.relname = {$this->connection->quote($table)} - ")->fetchColumn(0); - $columns = array(); foreach ($this->connection->query(" - SELECT * - FROM information_schema.columns - WHERE table_name = {$this->connection->quote($table)} AND table_schema = current_schema() - ORDER BY ordinal_position + SELECT + c.column_name AS name, + c.table_name AS table, + upper(c.udt_name) AS nativetype, + greatest(c.character_maximum_length, c.numeric_precision) AS size, + FALSE AS unsigned, + c.is_nullable = 'YES' AS nullable, + c.column_default AS default, + coalesce(tc.constraint_type = 'PRIMARY KEY', FALSE) AND strpos(c.column_default, 'nextval') = 1 AS autoincrement, + coalesce(tc.constraint_type = 'PRIMARY KEY', FALSE) AS primary + FROM + information_schema.columns AS c + LEFT JOIN information_schema.constraint_column_usage AS ccu USING(table_catalog, table_schema, table_name, column_name) + LEFT JOIN information_schema.table_constraints AS tc USING(constraint_catalog, constraint_schema, constraint_name) + WHERE + c.table_name = {$this->connection->quote($table)} + AND + c.table_schema = current_schema() + AND + (tc.constraint_type IS NULL OR tc.constraint_type = 'PRIMARY KEY') + ORDER BY + c.ordinal_position ") as $row) { - $size = (int) max($row['character_maximum_length'], $row['numeric_precision']); - $columns[] = array( - 'name' => $row['column_name'], - 'table' => $table, - 'nativetype' => strtoupper($row['udt_name']), - 'size' => $size ? $size : NULL, - 'nullable' => $row['is_nullable'] === 'YES', - 'default' => $row['column_default'], - 'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval', - 'primary' => (int) $row['ordinal_position'] === $primary, - 'vendor' => (array) $row, - ); + $row['vendor'] = array(); + $columns[] = (array) $row; } + return $columns; } @@ -153,31 +165,33 @@ public function getColumns($table) */ public function getIndexes($table) { - $columns = array(); - foreach ($this->connection->query(" - SELECT ordinal_position, column_name - FROM information_schema.columns - WHERE table_name = {$this->connection->quote($table)} AND table_schema = current_schema() - ORDER BY ordinal_position - ") as $row) { - $columns[$row['ordinal_position']] = $row['column_name']; - } - + /* There is no information about all indexes in information_schema, so pg catalog must be used */ $indexes = array(); foreach ($this->connection->query(" - SELECT pg_class2.relname, indisunique, indisprimary, indkey - FROM pg_class - LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid - INNER JOIN pg_class as pg_class2 on pg_class2.oid = pg_index.indexrelid - WHERE pg_class.relname = {$this->connection->quote($table)} + SELECT + c2.relname AS name, + indisunique AS unique, + indisprimary AS primary, + attname AS column + FROM + pg_class AS c1 + JOIN pg_namespace ON c1.relnamespace = pg_namespace.oid + JOIN pg_index ON c1.oid = indrelid + JOIN pg_class AS c2 ON indexrelid = c2.oid + LEFT JOIN pg_attribute ON c1.oid = attrelid AND attnum = ANY(indkey) + WHERE + nspname = current_schema() + AND + c1.relkind = 'r' + AND + c1.relname = {$this->connection->quote($table)} ") as $row) { - $indexes[$row['relname']]['name'] = $row['relname']; - $indexes[$row['relname']]['unique'] = $row['indisunique'] === 't'; - $indexes[$row['relname']]['primary'] = $row['indisprimary'] === 't'; - foreach (explode(' ', $row['indkey']) as $index) { - $indexes[$row['relname']]['columns'][] = $columns[$index]; - } + $indexes[$row['name']]['name'] = $row['name']; + $indexes[$row['name']]['unique'] = $row['unique']; + $indexes[$row['name']]['primary'] = $row['primary']; + $indexes[$row['name']]['columns'][] = $row['column']; } + return array_values($indexes); } @@ -188,7 +202,16 @@ public function getIndexes($table) */ public function getForeignKeys($table) { - throw new NotImplementedException; + return $this->connection->query(" + SELECT tc.table_name AS name, kcu.column_name AS local, ccu.table_name AS table, ccu.column_name AS foreign + FROM information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name AND tc.constraint_schema = kcu.constraint_schema + JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name AND ccu.constraint_schema = tc.constraint_schema + WHERE + constraint_type = 'FOREIGN KEY' AND + tc.table_name = {$this->connection->quote($table)} AND + tc.constraint_schema = current_schema() + ")->fetchAll(); } diff --git a/Nette/Database/Helpers.php b/Nette/Database/Helpers.php index 95f8469a04..646447e492 100644 --- a/Nette/Database/Helpers.php +++ b/Nette/Database/Helpers.php @@ -162,7 +162,7 @@ public static function loadFromFile(Connection $connection, $file) $count++; } } - if ($sql !== '') { + if (trim($sql) !== '') { $connection->exec($sql); $count++; } diff --git a/Nette/Database/Table/Selection.php b/Nette/Database/Table/Selection.php index d2d2a61893..2b8c9f842c 100644 --- a/Nette/Database/Table/Selection.php +++ b/Nette/Database/Table/Selection.php @@ -705,6 +705,7 @@ public function getReferencedTable($table, $column, $checkReferenceNewKeys = FAL $referenced = & $this->referenced["$table.$column"]; if ($referenced === NULL || $checkReferenceNewKeys || $this->checkReferenceNewKeys) { $keys = array(); + $this->execute(); foreach ($this->rows as $row) { if ($row[$column] === NULL) continue; @@ -744,10 +745,9 @@ public function getReferencingTable($table, $column, $active = NULL, $forceNewIn $referencing = & $this->referencing["$table:$column"]; if (!$referencing || $forceNewInstance) { $referencing = new GroupedSelection($table, $this, $column); - $referencing->where("$table.$column", array_keys((array) $this->rows)); // (array) - is NULL after insert } - return $referencing->setActive($active); + return $referencing->setActive($active)->where("$table.$column", array_keys((array) $this->rows)); } diff --git a/Nette/Diagnostics/Debugger.php b/Nette/Diagnostics/Debugger.php index 5fc982343d..f564f263b4 100644 --- a/Nette/Diagnostics/Debugger.php +++ b/Nette/Diagnostics/Debugger.php @@ -155,7 +155,7 @@ final public function __construct() */ public static function _init() { - self::$time = microtime(TRUE); + self::$time = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(TRUE); self::$consoleMode = PHP_SAPI === 'cli'; self::$productionMode = self::DETECT; if (self::$consoleMode) { @@ -231,10 +231,12 @@ public static function enable($mode = NULL, $logDirectory = NULL, $email = NULL) self::$productionMode = $mode; } elseif ($mode !== self::DETECT || self::$productionMode === NULL) { // IP addresses or computer names whitelist detection - $mode = is_string($mode) ? preg_split('#[,\s]+#', $mode) : (array) $mode; - $mode[] = '127.0.0.1'; - $mode[] = '::1'; - self::$productionMode = !in_array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'), $mode, TRUE); + $list = is_string($mode) ? preg_split('#[,\s]+#', $mode) : (array) $mode; + if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $list[] = '127.0.0.1'; + $list[] = '::1'; + } + self::$productionMode = !in_array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'), $list, TRUE); } // logging configuration @@ -606,7 +608,7 @@ public static function dump($var, $return = FALSE) } if (self::$consoleMode) { - if (self::$consoleColors && substr(PHP_OS, 0, 3) !== 'WIN') { + if (self::$consoleColors && substr(getenv('TERM'), 0, 5) === 'xterm') { $output = preg_replace_callback('#|#', function($m) { return "\033[" . (isset($m[1], Debugger::$consoleColors[$m[1]]) ? Debugger::$consoleColors[$m[1]] : '0') . "m"; }, $output); diff --git a/Nette/Diagnostics/templates/bar.phtml b/Nette/Diagnostics/templates/bar.phtml index 1eb2a894b2..4e1000a0de 100644 --- a/Nette/Diagnostics/templates/bar.phtml +++ b/Nette/Diagnostics/templates/bar.phtml @@ -308,6 +308,12 @@ use Nette; #nette-debug pre.nette-dump .php-visibility { font-size: 85%; color: #999; } + + @media print { + #nette-debug * { + display: none; + } + } ') { $this->output .= $token->text; @@ -308,7 +317,7 @@ private function processHtmlTagEnd($token) - private function processHtmlAttribute($token) + private function processHtmlAttribute(Token $token) { $htmlNode = end($this->htmlNodes); if (Strings::startsWith($token->name, Parser::N_PREFIX)) { @@ -330,6 +339,16 @@ private function processHtmlAttribute($token) + private function processComment(Token $token) + { + $isLeftmost = trim(substr($this->output, strrpos("\n$this->output", "\n"))) === ''; + if (!$isLeftmost) { + $this->output .= substr($token->text, strlen(rtrim($token->text, "\n"))); + } + } + + + /********************* macros ****************d*g**/ diff --git a/Nette/Latte/Macros/UIMacros.php b/Nette/Latte/Macros/UIMacros.php index 883ad44cb2..5f8834eb69 100644 --- a/Nette/Latte/Macros/UIMacros.php +++ b/Nette/Latte/Macros/UIMacros.php @@ -503,6 +503,7 @@ public static function renderSnippets(Nette\Application\UI\Control $control, \st } } } + $control->snippetMode = TRUE; if ($control instanceof Nette\Application\UI\IRenderable) { $queue = array($control); do { diff --git a/Nette/Latte/PhpWriter.php b/Nette/Latte/PhpWriter.php index 070c1e5dc9..39814bdfa2 100644 --- a/Nette/Latte/PhpWriter.php +++ b/Nette/Latte/PhpWriter.php @@ -247,7 +247,9 @@ public function preprocess(MacroTokenizer $tokenizer = NULL) } if ($token['value'] === '[') { // simplified array syntax [...] - if ($arrays[] = $prev['value'] !== ']' && $prev['type'] !== MacroTokenizer::T_SYMBOL && $prev['type'] !== MacroTokenizer::T_VARIABLE && $prev['type'] !== MacroTokenizer::T_KEYWORD) { + if ($arrays[] = $prev['value'] !== ']' && $prev['value'] !== ')' && $prev['type'] !== MacroTokenizer::T_SYMBOL + && $prev['type'] !== MacroTokenizer::T_VARIABLE && $prev['type'] !== MacroTokenizer::T_KEYWORD + ) { $tokens[] = MacroTokenizer::createToken('array') + array('depth' => $depth); $token = MacroTokenizer::createToken('('); } diff --git a/Nette/Reflection/ClassType.php b/Nette/Reflection/ClassType.php index 2e745f3117..040ca8dd1c 100644 --- a/Nette/Reflection/ClassType.php +++ b/Nette/Reflection/ClassType.php @@ -22,11 +22,11 @@ * @author David Grudl * @property-read Method $constructor * @property-read Extension $extension - * @property-read array $interfaces - * @property-read array $methods + * @property-read ClassType[] $interfaces + * @property-read Method[] $methods * @property-read ClassType $parentClass - * @property-read array $properties - * @property-read array $annotations + * @property-read Property[] $properties + * @property-read IAnnotation[][] $annotations * @property-read string $description * @property-read string $name * @property-read bool $internal @@ -36,8 +36,8 @@ * @property-read int $startLine * @property-read int $endLine * @property-read string $docComment - * @property-read array $constants - * @property-read array $interfaceNames + * @property-read mixed[] $constants + * @property-read string[] $interfaceNames * @property-read bool $interface * @property-read bool $abstract * @property-read bool $final @@ -171,7 +171,7 @@ public function is($type) /** - * @return Method + * @return Method|NULL */ public function getConstructor() { @@ -181,7 +181,7 @@ public function getConstructor() /** - * @return Extension + * @return Extension|NULL */ public function getExtension() { @@ -190,6 +190,9 @@ public function getExtension() + /** + * @return ClassType[] + */ public function getInterfaces() { $res = array(); @@ -210,7 +213,9 @@ public function getMethod($name) } - + /** + * @return Method[] + */ public function getMethods($filter = -1) { foreach ($res = parent::getMethods($filter) as $key => $val) { @@ -222,7 +227,7 @@ public function getMethods($filter = -1) /** - * @return ClassType + * @return ClassType|NULL */ public function getParentClass() { @@ -230,7 +235,9 @@ public function getParentClass() } - + /** + * @return Property[] + */ public function getProperties($filter = -1) { foreach ($res = parent::getProperties($filter) as $key => $val) { @@ -283,7 +290,7 @@ public function getAnnotation($name) /** * Returns all annotations. - * @return array + * @return IAnnotation[][] */ public function getAnnotations() { diff --git a/Nette/Reflection/GlobalFunction.php b/Nette/Reflection/GlobalFunction.php index 609c8caa52..07da1fc69d 100644 --- a/Nette/Reflection/GlobalFunction.php +++ b/Nette/Reflection/GlobalFunction.php @@ -23,7 +23,7 @@ * @property-read array $defaultParameters * @property-read bool $closure * @property-read Extension $extension - * @property-read array $parameters + * @property-read Parameter[] $parameters * @property-read bool $disabled * @property-read bool $deprecated * @property-read bool $internal @@ -37,7 +37,7 @@ * @property-read int $numberOfParameters * @property-read int $numberOfRequiredParameters * @property-read string $shortName - * @property-read intr $startLine + * @property-read int $startLine * @property-read array $staticVariables */ class GlobalFunction extends \ReflectionFunction @@ -91,6 +91,9 @@ public function getExtension() + /** + * @return Parameter[] + */ public function getParameters() { foreach ($res = parent::getParameters() as $key => $val) { diff --git a/Nette/Reflection/Method.php b/Nette/Reflection/Method.php index f90c56191e..f2fce96aab 100644 --- a/Nette/Reflection/Method.php +++ b/Nette/Reflection/Method.php @@ -24,8 +24,8 @@ * @property-read ClassType $declaringClass * @property-read Method $prototype * @property-read Extension $extension - * @property-read array $parameters - * @property-read array $annotations + * @property-read Parameter[] $parameters + * @property-read IAnnotation[][] $annotations * @property-read string $description * @property-read bool $public * @property-read bool $private @@ -120,6 +120,9 @@ public function getExtension() + /** + * @return Parameter[] + */ public function getParameters() { $me = array(parent::getDeclaringClass()->getName(), $this->getName()); @@ -163,7 +166,7 @@ public function getAnnotation($name) /** * Returns all annotations. - * @return array + * @return IAnnotation[][] */ public function getAnnotations() { diff --git a/Nette/Reflection/Parameter.php b/Nette/Reflection/Parameter.php index f508903a04..7345d7d9e7 100644 --- a/Nette/Reflection/Parameter.php +++ b/Nette/Reflection/Parameter.php @@ -83,7 +83,7 @@ public function getDeclaringClass() /** - * @return Method | FunctionReflection + * @return Method|GlobalFunction */ public function getDeclaringFunction() { diff --git a/Nette/Reflection/Property.php b/Nette/Reflection/Property.php index 55a5380ed2..8f4c1a64f4 100644 --- a/Nette/Reflection/Property.php +++ b/Nette/Reflection/Property.php @@ -21,7 +21,7 @@ * * @author David Grudl * @property-read ClassType $declaringClass - * @property-read array $annotations + * @property-read IAnnotation[][] $annotations * @property-read string $description * @property-read string $name * @property mixed $value @@ -90,7 +90,7 @@ public function getAnnotation($name) /** * Returns all annotations. - * @return array + * @return IAnnotation[][] */ public function getAnnotations() { diff --git a/Nette/Security/IResource.php b/Nette/Security/IResource.php index e6caab27e9..5cf632464b 100644 --- a/Nette/Security/IResource.php +++ b/Nette/Security/IResource.php @@ -27,6 +27,6 @@ interface IResource * Returns a string identifier of the Resource. * @return string */ - public function getResourceId(); + function getResourceId(); } diff --git a/Nette/Security/IRole.php b/Nette/Security/IRole.php index 227addb08a..9a0869e41b 100644 --- a/Nette/Security/IRole.php +++ b/Nette/Security/IRole.php @@ -27,6 +27,6 @@ interface IRole * Returns a string identifier of the Role. * @return string */ - public function getRoleId(); + function getRoleId(); } diff --git a/Nette/Templating/Helpers.php b/Nette/Templating/Helpers.php index fc4406bffe..bca1962ee6 100644 --- a/Nette/Templating/Helpers.php +++ b/Nette/Templating/Helpers.php @@ -272,7 +272,7 @@ public static function replace($subject, $search, $replacement = '') public static function dataStream($data, $type = NULL) { if ($type === NULL) { - $type = Nette\Utils\MimeTypeDetector::fromString($data, NULL); + $type = Nette\Utils\MimeTypeDetector::fromString($data); } return 'data:' . ($type ? "$type;" : '') . 'base64,' . base64_encode($data); } diff --git a/Nette/Templating/Template.php b/Nette/Templating/Template.php index 1addc13abc..6e980d437d 100644 --- a/Nette/Templating/Template.php +++ b/Nette/Templating/Template.php @@ -448,7 +448,10 @@ private static function extractPhp($source, & $blocks) continue; } elseif ($token[0] === T_CLOSE_TAG) { - $res .= str_repeat("\n", substr_count($php, "\n")) . $token[1]; + if ($php !== $res) { // not \x00-\x20!`](?:[^#,:=\]})>(\x00-\x1F]+|:(?!\s|$)|(?error(); } - $this->addValue($result, $hasKey, $key, $value); + $this->addValue($result, $hasKey, $key, $hasValue ? $value : NULL); $hasKey = $hasValue = FALSE; } elseif ($t === ':' || $t === '=') { // KeyValuePair separator @@ -213,8 +213,8 @@ private function parse($indent = NULL, $result = NULL) } elseif ($t[0] === "\n") { // Indent if ($inlineParser) { - if ($hasValue) { - $this->addValue($result, $hasKey, $key, $value); + if ($hasKey || $hasValue) { + $this->addValue($result, $hasKey, $key, $hasValue ? $value : NULL); $hasKey = $hasValue = FALSE; } @@ -291,10 +291,8 @@ private function parse($indent = NULL, $result = NULL) } if ($inlineParser) { - if ($hasValue) { - $this->addValue($result, $hasKey, $key, $value); - } elseif ($hasKey) { - $this->error(); + if ($hasKey || $hasValue) { + $this->addValue($result, $hasKey, $key, $hasValue ? $value : NULL); } } else { if ($hasValue && !$hasKey) { // block items must have "key" diff --git a/Nette/Utils/PhpGenerator/ClassType.php b/Nette/Utils/PhpGenerator/ClassType.php index eb9c0f431c..d995437fbc 100644 --- a/Nette/Utils/PhpGenerator/ClassType.php +++ b/Nette/Utils/PhpGenerator/ClassType.php @@ -121,7 +121,7 @@ public function __toString() $properties = array(); foreach ($this->properties as $property) { $properties[] = ($property->documents ? str_replace("\n", "\n * ", "/**\n" . implode("\n", (array) $property->documents)) . "\n */\n" : '') - . $property->visibility . ' $' . $property->name + . $property->visibility . ($property->static ? ' static' : '') . ' $' . $property->name . ($property->value === NULL ? '' : ' = ' . Helpers::dump($property->value)) . ";\n"; } diff --git a/Nette/Utils/PhpGenerator/Helpers.php b/Nette/Utils/PhpGenerator/Helpers.php index acfb02c344..995854e807 100644 --- a/Nette/Utils/PhpGenerator/Helpers.php +++ b/Nette/Utils/PhpGenerator/Helpers.php @@ -85,7 +85,7 @@ private static function _dump(&$var, $level = 0) foreach ($var as $k => &$v) { if ($k !== $marker) { $s .= "$space\t" . ($k === $counter ? '' : self::_dump($k) . " => ") . self::_dump($v, $level + 1) . ",\n"; - $counter = is_int($k) ? $k + 1 : $counter; + $counter = is_int($k) ? max($k + 1, $counter) : $counter; } } unset($var[$marker]); diff --git a/Nette/Utils/Strings.php b/Nette/Utils/Strings.php index ba211bcd26..45339ce996 100644 --- a/Nette/Utils/Strings.php +++ b/Nette/Utils/Strings.php @@ -163,7 +163,7 @@ public static function normalize($s) */ public static function toAscii($s) { - $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', '', $s); + $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s); $s = strtr($s, '`\'"^~', "\x01\x02\x03\x04\x05"); if (ICONV_IMPL === 'glibc') { $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT', $s); // intentionally @ diff --git a/Nette/Utils/Tokenizer.php b/Nette/Utils/Tokenizer.php index 66d2434e2b..43b8284d35 100644 --- a/Nette/Utils/Tokenizer.php +++ b/Nette/Utils/Tokenizer.php @@ -295,7 +295,6 @@ private function scan($wanted, $first, $advance = TRUE, $neg = FALSE, $prev = FA /** * The exception that indicates tokenizer error. - * @internal */ class TokenizerException extends \Exception { diff --git a/Nette/common/DateTime.php b/Nette/common/DateTime.php index 1b7fac59d5..7336e32c13 100644 --- a/Nette/common/DateTime.php +++ b/Nette/common/DateTime.php @@ -50,7 +50,7 @@ class DateTime extends \DateTime public static function from($time) { if ($time instanceof \DateTime) { - return clone $time; + return new self($time->format('Y-m-d H:i:s'), $time->getTimezone()); } elseif (is_numeric($time)) { if ($time <= self::YEAR) { diff --git a/Nette/common/Environment.php b/Nette/common/Environment.php index d455ab890c..633b1fe4a4 100644 --- a/Nette/common/Environment.php +++ b/Nette/common/Environment.php @@ -175,7 +175,7 @@ public static function setContext(DI\Container $context) /** * Get initial instance of context. - * @return Nette\DI\Container + * @return \SystemContainer|Nette\DI\Container */ public static function getContext() { diff --git a/Nette/common/Framework.php b/Nette/common/Framework.php index 678f134cd7..3051b80197 100644 --- a/Nette/common/Framework.php +++ b/Nette/common/Framework.php @@ -25,7 +25,7 @@ final class Framework /** Nette Framework version identification */ const NAME = 'Nette Framework', - VERSION = '2.0.3', + VERSION = '2.0.4', REVISION = '$WCREV$ released on $WCDATE$'; /** @var bool set to TRUE if your host has disabled function ini_set */ diff --git a/Nette/common/ObjectMixin.php b/Nette/common/ObjectMixin.php index 8e02b64034..79c70083bc 100644 --- a/Nette/common/ObjectMixin.php +++ b/Nette/common/ObjectMixin.php @@ -144,6 +144,14 @@ public static function & get($_this, $name) self::$methods[$class] = array_flip(get_class_methods($class)); } + // public method as closure getter + if (isset(self::$methods[$class][$name])) { + $val = function() use ($_this, $name) { + return call_user_func_array(array($_this, $name), func_get_args()); + }; + return $val; + } + // property getter support $name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character $m = 'get' . $name; diff --git a/Nette/loader.php b/Nette/loader.php index 3ad30652c1..e8d22a6fc3 100644 --- a/Nette/loader.php +++ b/Nette/loader.php @@ -1,7 +1,7 @@ constructUrl($request, $url); } diff --git a/tests/Nette/Application.Routers/Route.slash.phpt b/tests/Nette/Application.Routers/Route.slash.phpt new file mode 100644 index 0000000000..e50442bb7d --- /dev/null +++ b/tests/Nette/Application.Routers/Route.slash.phpt @@ -0,0 +1,36 @@ +', array( + 'presenter' => 'Presenter', +)); + +testRouteIn($route, '/a/b'); +Assert::null( testRouteOut($route, 'Presenter', array('param' => 'a/b')) ); + + +$route = new Route('', array( + 'presenter' => 'Presenter', +)); + +testRouteIn($route, '/a/b', 'Presenter', array( + 'param' => 'a/b', + 'test' => 'testvalue', +), '/a/b?test=testvalue'); diff --git a/tests/Nette/Application.UI/MicroPresenter.invoke.phpt b/tests/Nette/Application.UI/MicroPresenter.invoke.phpt new file mode 100644 index 0000000000..26cf51613e --- /dev/null +++ b/tests/Nette/Application.UI/MicroPresenter.invoke.phpt @@ -0,0 +1,52 @@ +setTempDirectory(TEMP_DIR)->createContainer(); + +$presenter = new NetteModule\MicroPresenter($container); + + +$presenter->run(new Request('Nette:Micro', 'GET', array( + 'callback' => function ($id, $page) { + TestHelpers::note('Callback id ' . $id . ' page ' . $page); + }, + 'id' => 1, + 'page' => 2, +))); +Assert::equal(array( + 'Callback id 1 page 2' +), TestHelpers::fetchNotes()); + + +$presenter->run(new Request('Nette:Micro', 'GET', array( + 'callback' => new Invokable(), + 'id' => 1, + 'page' => 2, +))); +Assert::equal(array( + 'Callback id 1 page 2' +), TestHelpers::fetchNotes()); diff --git a/tests/Nette/Application.UI/Presenter.link().phpt b/tests/Nette/Application.UI/Presenter.link().phpt index 0eb40c518a..a63021d248 100644 --- a/tests/Nette/Application.UI/Presenter.link().phpt +++ b/tests/Nette/Application.UI/Presenter.link().phpt @@ -20,7 +20,7 @@ require __DIR__ . '/../bootstrap.php'; class TestControl extends Application\UI\Control { /** @persistent array */ - public $order; + public $order = array(); /** @persistent int */ public $round = 0; @@ -40,15 +40,7 @@ class TestControl extends Application\UI\Control { if (isset($params['order'])) { $params['order'] = explode('.', $params['order']); - - // validate - $copy = $params['order']; - sort($copy); - if ($copy != range(0, self::MAX)) { - unset($params['order']); - } } - parent::loadState($params); } @@ -82,6 +74,9 @@ class TestPresenter extends Application\UI\Presenter /** @persistent @var bool */ public $ok = TRUE; + /** @persistent @var bool */ + public $var2 = FALSE; + protected function createTemplate($class = NULL) { @@ -97,8 +92,8 @@ class TestPresenter extends Application\UI\Presenter Assert::same( '/index.php?action=product&presenter=Test', $this->link('product', array('var1' => $this->var1)) ); Assert::same( '/index.php?var1=20&action=product&presenter=Test', $this->link('product', array('var1' => $this->var1 * 2, 'ok' => TRUE)) ); Assert::same( '/index.php?var1=1&ok=0&action=product&presenter=Test', $this->link('product', array('var1' => TRUE, 'ok' => '0')) ); - Assert::same( '/index.php?action=product&presenter=Test', $this->link('product', array('var1' => NULL, 'ok' => 'a')) ); - Assert::same( '/index.php?var1=1&ok=0&action=product&presenter=Test', $this->link('product', array('var1' => array(1), 'ok' => FALSE)) ); + Assert::same( "error: Invalid value for persistent parameter 'ok' in 'Test', expected boolean.", $this->link('product', array('var1' => NULL, 'ok' => 'a')) ); + Assert::same( "error: Invalid value for persistent parameter 'var1' in 'Test', expected integer.", $this->link('product', array('var1' => array(1), 'ok' => FALSE)) ); Assert::same( "error: Unable to pass parameters to action 'Test:product', missing corresponding method.", $this->link('product', 1, 2) ); Assert::same( '/index.php?x=1&y=2&action=product&presenter=Test', $this->link('product', array('x' => 1, 'y' => 2)) ); Assert::same( '/index.php?action=product&presenter=Test', $this->link('product') ); @@ -115,13 +110,19 @@ class TestPresenter extends Application\UI\Presenter Assert::same( '/index.php?action=default&do=buy&presenter=Test', $this->link('buy!', array('var1' => $this->var1)) ); Assert::same( '/index.php?var1=20&action=default&do=buy&presenter=Test', $this->link('buy!', array('var1' => $this->var1 * 2)) ); Assert::same( '/index.php?y=2&action=default&do=buy&presenter=Test', $this->link('buy!', 1, 2) ); - Assert::same( '/index.php?y=2&action=default&do=buy&presenter=Test', $this->link('buy!', '1', '2') ); + Assert::same( '/index.php?y=2&bool=1&str=1&action=default&do=buy&presenter=Test', $this->link('buy!', '1', '2', TRUE, TRUE) ); + Assert::same( '/index.php?y=2&str=0&action=default&do=buy&presenter=Test', $this->link('buy!', '1', '2', FALSE, FALSE) ); Assert::same( '/index.php?action=default&do=buy&presenter=Test', $this->link('buy!', array(1), (object) array(1)) ); Assert::same( '/index.php?y=2&action=default&do=buy&presenter=Test', $this->link('buy!', array(1, 'y' => 2)) ); Assert::same( '/index.php?y=2&action=default&do=buy&presenter=Test', $this->link('buy!', array('x' => 1, 'y' => 2, 'var1' => $this->var1)) ); Assert::same( 'error: Signal must be non-empty string.', $this->link('!') ); Assert::same( '/index.php?action=default&presenter=Test', $this->link('this', array('var1' => $this->var1)) ); Assert::same( '/index.php?action=default&presenter=Test', $this->link('this!', array('var1' => $this->var1)) ); + Assert::same( '/index.php?sort%5By%5D%5Basc%5D=1&action=default&presenter=Test', $this->link('this', array('sort' => array('y' => array('asc' => TRUE)))) ); + + // Presenter & signal link type checking + Assert::same( "error: Invalid value for parameter 'x' in method TestPresenter::handlebuy(), expected integer.", $this->link('buy!', array(array())) ); + Assert::same( "/index.php?action=default&do=buy&presenter=Test", $this->link('buy!', array(new stdClass)) ); // Component link Assert::same( 'error: Signal must be non-empty string.', $this->mycontrol->link('', 0, 1) ); @@ -136,15 +137,21 @@ class TestPresenter extends Application\UI\Presenter Assert::same( '/index.php?mycontrol-x=1&mycontrol-round=1&action=default&presenter=Test', $this->mycontrol->link('this', array('x' => 1, 'round' => 1)) ); Assert::same( '/index.php?mycontrol-x=1&mycontrol-round=1&action=default&presenter=Test', $this->mycontrol->link('this?x=1&round=1') ); Assert::same( '/index.php?mycontrol-x=1&mycontrol-round=1&action=default&presenter=Test#frag', $this->mycontrol->link('this?x=1&round=1#frag') ); - Assert::same( 'http://localhost/index.php?mycontrol-x=1&mycontrol-round=1&action=default&presenter=Test#frag', $this->mycontrol->link('//this?x=1&round=1#frag') ); + + // Component link type checking + Assert::same( "error: Invalid value for persistent parameter 'order' in 'mycontrol', expected array.", $this->mycontrol->link('click', array('order' => 1)) ); + Assert::same( "error: Invalid value for persistent parameter 'round' in 'mycontrol', expected integer.", $this->mycontrol->link('click', array('round' => array())) ); + $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; } /** * @view: default */ - public function handleBuy($x = 1, $y = 1) + public function handleBuy($x = 1, $y = 1, $bool = FALSE, $str = '') { } diff --git a/tests/Nette/Application.UI/Presenter.paramChecking.phpt b/tests/Nette/Application.UI/Presenter.paramChecking.phpt index 68e0940efe..27d6bb2d2d 100644 --- a/tests/Nette/Application.UI/Presenter.paramChecking.phpt +++ b/tests/Nette/Application.UI/Presenter.paramChecking.phpt @@ -19,6 +19,9 @@ require __DIR__ . '/../bootstrap.php'; class TestPresenter extends Application\UI\Presenter { + /** @persistent */ + public $bool = TRUE; + function actionDefault($a, $b = NULL, array $c, array $d = NULL, $e = 1, $f = 1.0, $g = FALSE) { } @@ -45,46 +48,51 @@ Assert::throws(function() use ($presenter) { Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('a' => array())); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'a', expected scalar."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'a' in method TestPresenter::actionDefault(), expected scalar."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('b' => array())); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'b', expected scalar."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'b' in method TestPresenter::actionDefault(), expected scalar."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('c' => 1)); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'c', expected array."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'c' in method TestPresenter::actionDefault(), expected array."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('d' => 1)); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'd', expected array."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'd' in method TestPresenter::actionDefault(), expected array."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('e' => 1.1)); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'e', expected integer."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'e' in method TestPresenter::actionDefault(), expected integer."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('e' => '1 ')); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'e', expected integer."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'e' in method TestPresenter::actionDefault(), expected integer."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('f' => '1 ')); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'f', expected double."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'f' in method TestPresenter::actionDefault(), expected double."); Assert::throws(function() use ($presenter) { $request = new Application\Request('Test', Http\Request::GET, array('g' => '')); $presenter->run($request); -}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'g', expected boolean."); +}, 'Nette\Application\BadRequestException', "Invalid value for parameter 'g' in method TestPresenter::actionDefault(), expected boolean."); + +Assert::throws(function() use ($presenter) { + $request = new Application\Request('Test', Http\Request::GET, array('bool' => array())); + $presenter->run($request); +}, 'Nette\Application\BadRequestException', "Invalid value for persistent parameter 'bool' in 'Test', expected boolean."); diff --git a/tests/Nette/Config/Configurator.productionMode.phpt b/tests/Nette/Config/Configurator.productionMode.phpt index 2a68aa54f1..8be9c47f7d 100644 --- a/tests/Nette/Config/Configurator.productionMode.phpt +++ b/tests/Nette/Config/Configurator.productionMode.phpt @@ -18,16 +18,22 @@ require __DIR__ . '/../bootstrap.php'; $configurator = new Configurator; -Assert::true( $configurator->isProductionMode() ); +Assert::false( $configurator->isDebugMode() ); -$configurator->setProductionMode(FALSE); -Assert::false( $configurator->isProductionMode() ); +$configurator->setDebugMode(TRUE); +Assert::true( $configurator->isDebugMode() ); +Assert::false( @$configurator->isProductionMode() ); -$configurator->setProductionMode(); -Assert::true( $configurator->isProductionMode() ); +$configurator->setDebugMode(FALSE); +Assert::false( $configurator->isDebugMode() ); +Assert::true( @$configurator->isProductionMode() ); -$configurator->setProductionMode(php_uname('n')); -Assert::false( $configurator->isProductionMode() ); +$configurator->setDebugMode(php_uname('n')); +Assert::true( $configurator->isDebugMode() ); -$configurator->setProductionMode(array(php_uname('n'))); -Assert::false( $configurator->isProductionMode() ); +$configurator->setDebugMode(array(php_uname('n'))); +Assert::true( $configurator->isDebugMode() ); + +$_SERVER['HTTP_X_FORWARDED_FOR'] = '127.0.0.1'; +Assert::false( $configurator::detectDebugMode() ); +Assert::true( $configurator::detectDebugMode(php_uname('n')) ); diff --git a/tests/Nette/Forms/Forms.example.001.expect b/tests/Nette/Forms/Forms.example.001.expect index 90689272a7..e71af7b92d 100644 --- a/tests/Nette/Forms/Forms.example.001.expect +++ b/tests/Nette/Forms/Forms.example.001.expect @@ -72,6 +72,12 @@ + + + + + + diff --git a/tests/Nette/Forms/Forms.example.001.phpt b/tests/Nette/Forms/Forms.example.001.phpt index 6a6439e977..b3b2df0ec3 100644 --- a/tests/Nette/Forms/Forms.example.001.phpt +++ b/tests/Nette/Forms/Forms.example.001.phpt @@ -86,6 +86,10 @@ $form->addSelect('country', 'Country:', $countries) ->addConditionOn($form['send'], Form::EQUAL, TRUE) ->addRule(Form::FILLED, 'Select your country'); +$form->addSelect('countrySetItems', 'Country:') + ->setPrompt('Select your country') + ->setItems($countries); + // group Your account $form->addGroup('Your account'); diff --git a/tests/Nette/Http/Session.storage.phpt b/tests/Nette/Http/Session.storage.phpt index 51a6d0e275..5ad5e65bbf 100644 --- a/tests/Nette/Http/Session.storage.phpt +++ b/tests/Nette/Http/Session.storage.phpt @@ -17,6 +17,9 @@ use Nette\Object, require __DIR__ . '/../bootstrap.php'; +ini_set('session.save_path', TEMP_DIR); + + class MySessionStorage extends Object implements ISessionStorage { diff --git a/tests/Nette/Latte/PhpWriter.formatArgs().phpt b/tests/Nette/Latte/PhpWriter.formatArgs().phpt index 8a012bab0f..280f4eff78 100644 --- a/tests/Nette/Latte/PhpWriter.formatArgs().phpt +++ b/tests/Nette/Latte/PhpWriter.formatArgs().phpt @@ -73,6 +73,7 @@ Assert::same( "'symbol' => \$this -> var, ", formatArgs('symbol => $this -> var Assert::same( "'symbol' => \$this -> var", formatArgs('symbol => $this -> var') ); Assert::same( "'symbol1' => 'value'", formatArgs('symbol1 => /*value,* /symbol2=>*/value/**/') ); Assert::same( "(array)", formatArgs('(array)') ); +Assert::same( 'func()[1]', formatArgs('func()[1]') ); // special UTF-8 diff --git a/tests/Nette/Latte/UIMacros.renderSnippets.phpt b/tests/Nette/Latte/UIMacros.renderSnippets.phpt index 90f9922347..c29b3ede2a 100644 --- a/tests/Nette/Latte/UIMacros.renderSnippets.phpt +++ b/tests/Nette/Latte/UIMacros.renderSnippets.phpt @@ -58,7 +58,7 @@ class MultiControl extends Nette\Application\UI\Presenter } -$control = new MultiControl(new Nette\Di\Container(array( +$control = new MultiControl(new Nette\DI\Container(array( 'productionMode' => true, ))); $control['multi-1']; diff --git a/tests/Nette/Latte/UIMacros.renderSnippets2.phpt b/tests/Nette/Latte/UIMacros.renderSnippets2.phpt new file mode 100644 index 0000000000..1cf33ddf60 --- /dev/null +++ b/tests/Nette/Latte/UIMacros.renderSnippets2.phpt @@ -0,0 +1,91 @@ +renderA(); + $this->renderB(); + } + public function renderA() + { + $template = new Nette\Templating\Template; + $template->registerFilter(new Latte\Engine); + $template->_presenter = $this->getPresenter(); + $template->_control = $this; + $template->say = 'Hello'; + $template->setSource('{snippet testA}{$say}{/snippet}'); + $template->render(); + } + public function renderB() + { + $template = new Nette\Templating\Template; + $template->registerFilter(new Latte\Engine); + $template->_presenter = $this->getPresenter(); + $template->_control = $this; + $template->say = 'world'; + $template->setSource('{snippet testB}{$say}{/snippet}'); + $template->render(); + } + +} + +class TestPresenter extends Nette\Application\UI\Presenter +{ + private $payload; + function getPayload() + { + return $this->payload; + } + function emptyPayload() + { + $this->payload = (object) NULL; + } + function createComponentMulti() + { + return new Nette\Application\UI\Multiplier(function() { + return new InnerControl(); + }); + } + public function render() + { + $template = new Nette\Templating\Template; + $template->registerFilter(new Latte\Engine); + $template->_control = $this; + $template->render(); + } +} + + +$control = new TestPresenter(new Nette\DI\Container(array( + 'productionMode' => true, +))); +$control->snippetMode = true; + + + +$control->emptyPayload(); +$control['multi-1']->invalidateControl(); +$control->render(); +Assert::equal((object) array( + 'snippets' => array( + 'snippet-multi-1-testA' => 'Hello', + 'snippet-multi-1-testB' => 'world', + ), +), $control->payload); diff --git a/tests/Nette/Latte/macros.contentType.phpt b/tests/Nette/Latte/macros.status.phpt similarity index 91% rename from tests/Nette/Latte/macros.contentType.phpt rename to tests/Nette/Latte/macros.status.phpt index acd3d048a8..74d1486cbe 100644 --- a/tests/Nette/Latte/macros.contentType.phpt +++ b/tests/Nette/Latte/macros.status.phpt @@ -1,7 +1,7 @@ setSource(<<setSource(<<sourceLine); Assert::same("Unknown macro {notDefined}", $e->getMessage()); } + +try { + $template->setSource( + '{* + *} + + {notDefined line 4} + ')->compile(); +} catch(\Nette\Latte\CompileException $e) { + Assert::same(4, $e->sourceLine); + Assert::same("Unknown macro {notDefined}", $e->getMessage()); +} diff --git a/tests/Nette/Utils/Neon.decode.001.phpt b/tests/Nette/Utils/Neon.decode.001.phpt index 4450b3dacd..ab090e074a 100644 --- a/tests/Nette/Utils/Neon.decode.001.phpt +++ b/tests/Nette/Utils/Neon.decode.001.phpt @@ -29,6 +29,7 @@ Assert::same( 'the"string#literal', Neon::decode('the"string#literal') ); Assert::same( 'the"string', Neon::decode('the"string #literal') ); Assert::same( "the'string #literal", Neon::decode('"the\'string #literal"') ); Assert::same( 'the"string #literal', Neon::decode("'the\"string #literal'") ); +Assert::same( ' ', Neon::decode(' ') ); Assert::same( "", Neon::decode("''") ); Assert::same( "", Neon::decode('""') ); Assert::same( ':a', Neon::decode(':a') ); diff --git a/tests/Nette/Utils/Neon.decode.002.phpt b/tests/Nette/Utils/Neon.decode.002.phpt index a2fdfbc65a..bfd691e561 100644 --- a/tests/Nette/Utils/Neon.decode.002.phpt +++ b/tests/Nette/Utils/Neon.decode.002.phpt @@ -36,7 +36,19 @@ Assert::same( array( 'c' => 'd', ), 'e' => 'f', -), Neon::decode('{a, b, {c: d}, e: f,}') ); + 'g' => NULL, + 'h' => NULL, +), Neon::decode('{a, b, {c: d}, e: f, g:,h:}') ); + + +Assert::same( array( + 'a', + 'b', + 'c' => 1, + 'd' => 1, + 'e' => 1, + 'f' => NULL, +), Neon::decode("{a,\nb\nc: 1,\nd: 1,\n\ne: 1\nf:\n}") ); Assert::true( Neon::decode('@item(a, b)') instanceof Nette\Utils\NeonEntity ); @@ -48,6 +60,12 @@ Assert::same( array( ), (array) Neon::decode('@item(a, b)') ); +Assert::same( array( + 'value' => '@item', + 'attributes' => array('a', 'b'), +), (array) Neon::decode('@item(a, b)') ); + + Assert::same( array( 'value' => 'item', 'attributes' => array('a', 'b'), diff --git a/tests/Nette/Utils/Neon.decode.003.phpt b/tests/Nette/Utils/Neon.decode.003.phpt index fe76915e14..2291400267 100644 --- a/tests/Nette/Utils/Neon.decode.003.phpt +++ b/tests/Nette/Utils/Neon.decode.003.phpt @@ -34,3 +34,13 @@ Assert::throws(function() { Assert::throws(function() { Neon::decode('item [a, b]'); }, 'Nette\Utils\NeonException', "Unexpected ',' on line 1, column 7." ); + + +Assert::throws(function() { + Neon::decode('{,}'); +}, 'Nette\Utils\NeonException', "Unexpected ',' on line 1, column 1." ); + + +Assert::throws(function() { + Neon::decode('{a, ,}'); +}, 'Nette\Utils\NeonException', "Unexpected ',' on line 1, column 4." ); diff --git a/tests/Nette/Utils/Neon.decode.004.phpt b/tests/Nette/Utils/Neon.decode.004.phpt new file mode 100644 index 0000000000..e209ca1080 --- /dev/null +++ b/tests/Nette/Utils/Neon.decode.004.phpt @@ -0,0 +1,41 @@ + array(1, 2), + 'b' => 1, +), Neon::decode(' +a: {1, 2, } +b: 1') ); + + +Assert::same( array( + 'a' => 'x', + 'x', +), Neon::decode(' +a: x +- x') ); + + +Assert::same( array( + 'x', + 'a' => 'x', +), Neon::decode(' +- x +a: x +') ); diff --git a/tests/Nette/Utils/Neon.encode.001.phpt b/tests/Nette/Utils/Neon.encode.001.phpt index f94d1b1eb3..2567e3a96e 100644 --- a/tests/Nette/Utils/Neon.encode.001.phpt +++ b/tests/Nette/Utils/Neon.encode.001.phpt @@ -55,6 +55,11 @@ Assert::equal( Neon::encode(Neon::decode('item(a, b)')) ); +Assert::equal( + 'item(a, b)', + Neon::encode(Neon::decode('item(a, b)')) +); + Assert::equal( 'item(foo: a, bar: b)', Neon::encode(Neon::decode('item(foo: a, bar: b)')) diff --git a/tests/Nette/Utils/NeonParser.syntax.txt b/tests/Nette/Utils/NeonParser.syntax.txt index 43a33c4a8d..20c5340487 100644 --- a/tests/Nette/Utils/NeonParser.syntax.txt +++ b/tests/Nette/Utils/NeonParser.syntax.txt @@ -1,7 +1,7 @@ Preprocessing ------------- - tabs are converted to single space -- \r is deleted +- \r is removed Comment @@ -9,39 +9,24 @@ Comment Comment ::= '#' .* -Values --------------- -Value ::= Boolean | Null | integer | float | String | Literal | InlineArray | Object +Values +------ +Value ::= Boolean | Null | integer | float | String | DateTime | Literal | InlineArray | Entity Boolean ::= 'true' | 'TRUE' | 'false' | 'FALSE' | 'yes' | 'YES' | 'no' | 'NO' Null ::= 'null' | 'NULL' | '' String ::= "word\u231" | 'word' -Literal ::= trimmed stream of characters [^#"',:=@[\]{}()<>\s] ( [^#,:=\]})>\n] | ':' \S | \S '#' )* +Literal ::= trimmed stream of characters [^#"',:=@[\]{}()\s!`] ( [^#,:=\]})(] | ':' [^\s,\]})] | \S '#' )* +Entity ::= Value '(' ( ArrayEntry ',' )* ')' InlineArray ----------- -InlineArray ::= '{' ( ArrayEntry ',' )* '}' | '[' ( ArrayEntry ',' )* ']' +InlineArray ::= '{' ( ArrayEntry ',' )* '}' | '[' ( ArrayEntry ',' )* ']' | '(' ( ArrayEntry ',' )* ')' ArrayEntry ::= Value | KeyValuePair -KeyValuePair ::= Key '=' Value | Key ': ' Value -Key ::= integer | String | Literal - - -Object ------- -Object ::= '@' ClassName '(' ( ArrayEntry ',' )* ')' - -ClassName ::= [a-zA-Z_0-9\]+ +KeyValuePair ::= Value '=' Value | Value ': ' Value BlockArray ---------- -BlockArray ::= Indent '- ' Value EOL - - -BlockHash ---------- -BlockHash ::= Indent Key ': ' KeyValuePair EOL - -NestedBlockHash ::= Indent Key ':' EOL - Indent Value +BlockArray ::= Indent ( '- ' Value | KeyValuePair ) EOL diff --git a/tests/Nette/Utils/PhpGenerator.class.expect b/tests/Nette/Utils/PhpGenerator.class.expect index 365bd60c91..f2c152f047 100644 --- a/tests/Nette/Utils/PhpGenerator.class.expect +++ b/tests/Nette/Utils/PhpGenerator.class.expect @@ -20,7 +20,7 @@ abstract final class Example extends ParentClass implements IExample, IOne public $order = RecursiveIteratorIterator::SELF_FIRST; - public $sections = array( + public static $sections = array( 'first' => TRUE, ); diff --git a/tests/Nette/Utils/PhpGenerator.dump.phpt b/tests/Nette/Utils/PhpGenerator.dump.phpt index 0cb6b85212..a6e209fbd0 100644 --- a/tests/Nette/Utils/PhpGenerator.dump.phpt +++ b/tests/Nette/Utils/PhpGenerator.dump.phpt @@ -39,7 +39,7 @@ Assert::same( 'array()', Helpers::dump(array()) ); Assert::same( "array(\n\t\$s,\n)", Helpers::dump(array(new PhpLiteral('$s'))) ); Assert::same( "array(\n\t1,\n\t2,\n\t3,\n)", Helpers::dump(array(1,2,3)) ); -Assert::same( "array(\n\t'a',\n\t7 => 'b',\n\t'c',\n\t'9a' => 'd',\n\t'e',\n)", Helpers::dump(array('a', 7 => 'b', 'c', '9a' => 'd', 'e')) ); +Assert::same( "array(\n\t'a',\n\t7 => 'b',\n\t'c',\n\t'9a' => 'd',\n\t'e',\n)", Helpers::dump(array('a', 7 => 'b', 'c', '9a' => 'd', 9 => 'e')) ); Assert::same( "array(\n\t'a' => 1,\n\tarray(\n\t\t\"\\r\" => \"\\r\",\n\t\t2,\n\t),\n\t3,\n)", Helpers::dump(array('a' => 1, array("\r" => "\r", 2), 3)) ); Assert::same( "(object) array(\n\t'a' => 1,\n\t'b' => 2,\n)", Helpers::dump((object) array('a' => 1, 'b' => 2)) ); diff --git a/tests/Nette/Utils/Strings.toAscii().phpt b/tests/Nette/Utils/Strings.toAscii().phpt index 54f382b982..45204bc34a 100644 --- a/tests/Nette/Utils/Strings.toAscii().phpt +++ b/tests/Nette/Utils/Strings.toAscii().phpt @@ -17,4 +17,5 @@ require __DIR__ . '/../bootstrap.php'; Assert::same( 'ZLUTOUCKY KUN oooo', Strings::toAscii("\xc5\xbdLU\xc5\xa4OU\xc4\x8cK\xc3\x9d K\xc5\xae\xc5\x87 \xc3\xb6\xc5\x91\xc3\xb4o") ); // ŽLUŤOUČKÝ KŮŇ öőôo +Assert::same( 'Zlutoucky kun', Strings::toAscii("Z\xCC\x8Clut\xCC\x8Couc\xCC\x8Cky\xCC\x81 ku\xCC\x8An\xCC\x8C") ); // Žluťoučký kůň with combining characters Assert::same( 'Z `\'"^~', Strings::toAscii("\xc5\xbd `'\"^~") ); diff --git a/tests/Nette/common/DateTime.from.phpt b/tests/Nette/common/DateTime.from.phpt new file mode 100644 index 0000000000..914b46cc02 --- /dev/null +++ b/tests/Nette/common/DateTime.from.phpt @@ -0,0 +1,26 @@ +format('Y-m-d H:i:s') ); Assert::same( 'Europe/London', $obj->getTimezone()->getName() ); @@ -34,7 +34,7 @@ Assert::same( 254397600, $obj->getTimestamp() ); -$obj = new DateTime53(NULL, new DateTimeZone('Europe/London')); +$obj = new Nette\DateTime(NULL, new DateTimeZone('Europe/London')); $obj->setTimestamp(254400000); Assert::same( '1978-01-23 10:40:00', $obj->format('Y-m-d H:i:s') ); @@ -47,17 +47,3 @@ $obj = unserialize(serialize($obj)); Assert::same( '1978-01-23 10:40:00', $obj->format('Y-m-d H:i:s') ); Assert::same( 'Europe/London', $obj->getTimezone()->getName() ); Assert::same( 254400000, $obj->getTimestamp() ); - - - -$obj = new DateTime53('2010-01-01 12:00:00'); -$ts = $obj->getTimestamp(); -$obj->setTimestamp($ts); -Assert::same($ts, $obj->getTimestamp()); - -$obj->setTimezone(new DateTimeZone('Indian/Comoro')); -$obj->setTimestamp($ts); -Assert::same($ts, $obj->getTimestamp()); - -$obj->setTimezone(new DateTimeZone('UTC')); -Assert::same($ts, $obj->getTimestamp()); diff --git a/tests/Nette/common/DateTime.timestamp.phpt b/tests/Nette/common/DateTime.timestamp.phpt new file mode 100644 index 0000000000..3de8870406 --- /dev/null +++ b/tests/Nette/common/DateTime.timestamp.phpt @@ -0,0 +1,31 @@ +getTimestamp(); +$obj->setTimestamp($ts); +Assert::same($ts, $obj->getTimestamp()); + +$obj->setTimezone(new DateTimeZone('Indian/Comoro')); +$obj->setTimestamp($ts); +Assert::same($ts, $obj->getTimestamp()); + +$obj->setTimezone(new DateTimeZone('UTC')); +Assert::same($ts, $obj->getTimestamp()); diff --git a/tests/Nette/common/Object.arrayProperty.phpt b/tests/Nette/common/Object.arrayProperty.phpt index 9a0aa50e7a..6fa9e8f963 100644 --- a/tests/Nette/common/Object.arrayProperty.phpt +++ b/tests/Nette/common/Object.arrayProperty.phpt @@ -13,9 +13,29 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; +class TestClass extends Nette\Object +{ + private $items; + + function __construct() + { + $this->items = new ArrayObject; + } + + public function getItems() + { + return $this->items; + } + + public function setItems(array $value) + { + $this->items = new ArrayObject($value); + } + +} + $obj = new TestClass; $obj->items[] = 'test'; diff --git a/tests/Nette/common/Object.events.phpt b/tests/Nette/common/Object.events.phpt index 4de5da9051..e9a8e78e72 100644 --- a/tests/Nette/common/Object.events.phpt +++ b/tests/Nette/common/Object.events.phpt @@ -13,7 +13,19 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; + + +class TestClass extends Nette\Object +{ + public $onPublic; + + static public $onPublicStatic; + + protected $onProtected; + + private $onPrivate; + +} @@ -53,6 +65,16 @@ Assert::same( 3, $var->counter ); +Assert::throws(function() use ($obj) { + $obj->onPublicStatic(123); +}, 'Nette\MemberAccessException', 'Call to undefined method TestClass::onPublicStatic().'); + + +Assert::throws(function() use ($obj) { + $obj->onProtected(123); +}, 'Nette\MemberAccessException', 'Call to undefined method TestClass::onProtected().'); + + Assert::throws(function() use ($obj) { $obj->onPrivate(123); }, 'Nette\MemberAccessException', 'Call to undefined method TestClass::onPrivate().'); diff --git a/tests/Nette/common/Object.extensionMethod.phpt b/tests/Nette/common/Object.extensionMethod.phpt index 84f90bb8eb..0e1ac3758b 100644 --- a/tests/Nette/common/Object.extensionMethod.phpt +++ b/tests/Nette/common/Object.extensionMethod.phpt @@ -13,16 +13,21 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; +class TestClass extends Nette\Object +{ + public $foo = 'Hello', $bar = 'World'; +} + function TestClass_join(TestClass $that, $separator) { return $that->foo . $separator . $that->bar; } + TestClass::extensionMethod('TestClass::join', 'TestClass_join'); -$obj = new TestClass('Hello', 'World'); +$obj = new TestClass; Assert::same( 'Hello*World', $obj->join('*') ); diff --git a/tests/Nette/common/Object.extensionMethod53.phpt b/tests/Nette/common/Object.extensionMethod53.phpt index e007467d7b..ed50b09179 100644 --- a/tests/Nette/common/Object.extensionMethod53.phpt +++ b/tests/Nette/common/Object.extensionMethod53.phpt @@ -14,9 +14,13 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; +class TestClass extends Nette\Object +{ + public $foo = 'Hello', $bar = 'World'; +} + TestClass::extensionMethod('join', function (TestClass $that, $separator) { @@ -24,5 +28,5 @@ TestClass::extensionMethod('join', } ); -$obj = new TestClass('Hello', 'World'); +$obj = new TestClass; Assert::same( 'Hello*World', $obj->join('*') ); diff --git a/tests/Nette/common/Object.extensionMethodOldWay.phpt b/tests/Nette/common/Object.extensionMethodOldWay.phpt index a5abafb2a6..c2212904eb 100644 --- a/tests/Nette/common/Object.extensionMethodOldWay.phpt +++ b/tests/Nette/common/Object.extensionMethodOldWay.phpt @@ -13,20 +13,22 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; - - - if (NETTE_PACKAGE === '5.3') { TestHelpers::skip('Requires Nette Framework package < PHP 5.3'); } +class TestClass extends Nette\Object +{ + public $foo = 'Hello', $bar = 'World'; +} + + function TestClass_prototype_join(TestClass $that, $separator) { return $that->foo . $separator . $that->bar; } -$obj = new TestClass('Hello', 'World'); +$obj = new TestClass; Assert::same( 'Hello*World', $obj->join('*') ); diff --git a/tests/Nette/common/Object.extensionMethodViaInterface.phpt b/tests/Nette/common/Object.extensionMethodViaInterface.phpt index 52943e7701..e52deefadd 100644 --- a/tests/Nette/common/Object.extensionMethodViaInterface.phpt +++ b/tests/Nette/common/Object.extensionMethodViaInterface.phpt @@ -14,7 +14,18 @@ use Nette\Reflection; require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; + + +interface IFirst +{} + +interface ISecond extends IFirst +{} + +class TestClass extends Nette\Object implements ISecond +{ + public $foo = 'Hello', $bar = 'World'; +} @@ -35,5 +46,5 @@ function ISecond_join(ISecond $that, $separator) Reflection\ClassType::from('IFirst')->setExtensionMethod('join', 'IFirst_join'); Reflection\ClassType::from('ISecond')->setExtensionMethod('join', 'ISecond_join'); -$obj = new TestClass('Hello', 'World'); +$obj = new TestClass; Assert::same( 'ISecond_join says Hello*World', $obj->join('*') ); diff --git a/tests/Nette/common/Object.inc b/tests/Nette/common/Object.inc deleted file mode 100644 index 5bd056fcaf..0000000000 --- a/tests/Nette/common/Object.inc +++ /dev/null @@ -1,92 +0,0 @@ -foo = $foo; - $this->bar = $bar; - $this->items = new ArrayObject; - } - - - - public function getFoo() - { - return $this->foo; - } - - - - public function setFoo($foo) - { - $this->foo = $foo; - } - - - - public function getBar() - { - return $this->bar; - } - - - - public function setBazz($value) - { - $this->bar = $value; - } - - - - public function getItems() - { - return $this->items; - } - - - - public function setItems(array $value) - { - $this->items = new ArrayObject($value); - } - - - - public function gets() // or setupXyz, settle... - { - echo __METHOD__; - return 'ERROR'; - } - -} diff --git a/tests/Nette/common/Object.methodGetter.phpt b/tests/Nette/common/Object.methodGetter.phpt new file mode 100644 index 0000000000..b620ee4f1b --- /dev/null +++ b/tests/Nette/common/Object.methodGetter.phpt @@ -0,0 +1,58 @@ +id = $id; + } + + public function publicMethod($a, $b) + { + return "$this->id $a $b"; + } + + protected function protectedMethod() + { + } + + private function privateMethod() + { + } + +} + + + +$obj1 = new TestClass(1); +$method = $obj1->publicMethod; +Assert::same( "1 2 3", $method(2, 3) ); + + +Assert::throws(function() { + $obj = new TestClass; + $method = $obj->protectedMethod; +}, 'Nette\MemberAccessException', 'Cannot read an undeclared property TestClass::$protectedMethod.'); + + +Assert::throws(function() { + $obj = new TestClass; + $method = $obj->privateMethod; +}, 'Nette\MemberAccessException', 'Cannot read an undeclared property TestClass::$privateMethod.'); diff --git a/tests/Nette/common/Object.property.phpt b/tests/Nette/common/Object.property.phpt index e8ab99ebfa..4791e42f1d 100644 --- a/tests/Nette/common/Object.property.phpt +++ b/tests/Nette/common/Object.property.phpt @@ -13,7 +13,45 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; + + +class TestClass extends Nette\Object +{ + private $foo, $bar; + + function __construct($foo = NULL, $bar = NULL) + { + $this->foo = $foo; + $this->bar = $bar; + } + + public function getFoo() + { + return $this->foo; + } + + public function setFoo($foo) + { + $this->foo = $foo; + } + + public function getBar() + { + return $this->bar; + } + + public function setBazz($value) + { + $this->bar = $value; + } + + public function gets() // or setupXyz, settle... + { + echo __METHOD__; + return 'ERROR'; + } + +} diff --git a/tests/Nette/common/Object.referenceProperty.phpt b/tests/Nette/common/Object.referenceProperty.phpt index 9c32e4dde9..5726861214 100644 --- a/tests/Nette/common/Object.referenceProperty.phpt +++ b/tests/Nette/common/Object.referenceProperty.phpt @@ -13,9 +13,24 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; +class TestClass extends Nette\Object +{ + private $foo; + + public function getFoo() + { + return $this->foo; + } + + public function setFoo($foo) + { + $this->foo = $foo; + } + +} + $obj = new TestClass; $obj->foo = 'hello'; diff --git a/tests/Nette/common/Object.reflection.phpt b/tests/Nette/common/Object.reflection.phpt index b29d00a08c..d9072f415d 100644 --- a/tests/Nette/common/Object.reflection.phpt +++ b/tests/Nette/common/Object.reflection.phpt @@ -13,9 +13,12 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; +class TestClass extends Nette\Object +{ +} + $obj = new TestClass; Assert::same( 'TestClass', $obj->getReflection()->getName() ); diff --git a/tests/Nette/common/Object.undeclaredMethod.phpt b/tests/Nette/common/Object.undeclaredMethod.phpt index 7c009e8550..47d072f9ad 100644 --- a/tests/Nette/common/Object.undeclaredMethod.phpt +++ b/tests/Nette/common/Object.undeclaredMethod.phpt @@ -13,9 +13,12 @@ require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/Object.inc'; +class TestClass extends Nette\Object +{ +} + Assert::throws(function() { $obj = new TestClass; diff --git a/tests/Test/Assert.php b/tests/Test/Assert.php index d752cc043d..9416ce5972 100644 --- a/tests/Test/Assert.php +++ b/tests/Test/Assert.php @@ -276,9 +276,14 @@ public static function match($expected, $actual) private static function doFail($message) { $trace = debug_backtrace(); - $trace = end($trace); - if (isset($trace['line'])) { - $message .= " on line $trace[line]"; + while (isset($trace[0]['file']) && $trace[0]['file'] === __FILE__) { + array_shift($trace); + } + if (isset($trace[0]['file'])) { + $message .= ' in file ' . $trace[0]['file']; + } + if (isset($trace[0]['line'])) { + $message .= ' on line ' . $trace[0]['line']; } echo "\n$message"; exit(TestCase::CODE_FAIL); @@ -403,7 +408,7 @@ private static function dumpPhp(&$var, $level = 0) foreach ($var as $k => &$v) { if ($k !== $marker) { $s .= "$space\t" . ($k === $counter ? '' : self::dumpPhp($k) . " => ") . self::dumpPhp($v, $level + 1) . ",\n"; - $counter = is_int($k) ? $k + 1 : $counter; + $counter = is_int($k) ? max($k + 1, $counter) : $counter; } } unset($var[$marker]); diff --git a/tests/Test/TestHelpers.php b/tests/Test/TestHelpers.php index 47bcbab69c..9d25cebd55 100644 --- a/tests/Test/TestHelpers.php +++ b/tests/Test/TestHelpers.php @@ -120,7 +120,10 @@ public static function prepareSaveCoverage() */ public static function saveCoverage() { - $coverage = @unserialize(file_get_contents(self::$coverageFile)); + $f = fopen(self::$coverageFile, 'a+'); + flock($f, LOCK_EX); + fseek($f, 0); + $coverage = @unserialize(stream_get_contents($f)); $root = realpath(__DIR__ . '/../../Nette') . DIRECTORY_SEPARATOR; foreach (xdebug_get_code_coverage() as $filename => $lines) { @@ -135,7 +138,9 @@ public static function saveCoverage() } } - file_put_contents(self::$coverageFile, serialize($coverage)); + ftruncate($f, 0); + fwrite($f, serialize($coverage)); + fclose($f); } } diff --git a/tests/php.ini b/tests/php.ini index 3b00b3583d..0218cb73b7 100644 --- a/tests/php.ini +++ b/tests/php.ini @@ -697,7 +697,7 @@ extension=php_pdo_sqlite.dll ;extension=php_snmp.dll ;extension=php_soap.dll ;extension=php_sockets.dll -extension=php_sqlite.dll +;extension=php_sqlite.dll ;extension=php_sybase_ct.dll ;extension=php_tidy.dll ;extension=php_xmlrpc.dll diff --git a/version.txt b/version.txt index 03096dc725..268208a132 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -Nette Framework 2.0.3 (revision $WCREV$ released on $WCDATE$) +Nette Framework 2.0.4 (revision $WCREV$ released on $WCDATE$)