From 466cd0b0c4f7655eabd62cfe983a1c5cdd527252 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 22 Jan 2017 13:41:43 +0100 Subject: [PATCH 01/16] fixed phpDoc --- src/PhpGenerator/ClassType.php | 4 ++++ src/PhpGenerator/Factory.php | 13 ++++++++++++- src/PhpGenerator/Helpers.php | 10 +++++++++- src/PhpGenerator/Method.php | 7 +++++-- src/PhpGenerator/PhpLiteral.php | 3 +++ src/PhpGenerator/PhpNamespace.php | 3 +++ 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index 46a74150..c20d30e1 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -76,6 +76,9 @@ public static function from($from) } + /** + * @param string|NULL + */ public function __construct($name = NULL, PhpNamespace $namespace = NULL) { $this->setName($name); @@ -403,6 +406,7 @@ public function addConst($name, $value) /** + * @param Constant[]|mixed[] * @return static */ public function setConstants(array $consts) diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 239c3da0..13b59adf 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -17,7 +17,9 @@ class Factory { use Nette\SmartObject; - + /** + * @return ClassType + */ public function fromClassReflection(\ReflectionClass $from) { if (PHP_VERSION_ID >= 70000 && $from->isAnonymous()) { @@ -51,6 +53,9 @@ public function fromClassReflection(\ReflectionClass $from) } + /** + * @return Method + */ public function fromFunctionReflection(\ReflectionFunctionAbstract $from) { $method = new Method($from->isClosure() ? NULL : $from->getName()); @@ -78,6 +83,9 @@ public function fromFunctionReflection(\ReflectionFunctionAbstract $from) } + /** + * @return Parameter + */ public function fromParameterReflection(\ReflectionParameter $from) { $param = new Parameter($from->getName()); @@ -109,6 +117,9 @@ public function fromParameterReflection(\ReflectionParameter $from) } + /** + * @return Property + */ public function fromPropertyReflection(\ReflectionProperty $from) { $prop = new Property($from->getName()); diff --git a/src/PhpGenerator/Helpers.php b/src/PhpGenerator/Helpers.php index 0217a4c7..53ddc939 100644 --- a/src/PhpGenerator/Helpers.php +++ b/src/PhpGenerator/Helpers.php @@ -149,6 +149,7 @@ private static function _dump(&$var, $level = 0) /** * Generates PHP statement. + * @param string * @return string */ public static function format($statement, ...$args) @@ -159,6 +160,7 @@ public static function format($statement, ...$args) /** * Generates PHP statement. + * @param string * @return string */ public static function formatArgs($statement, array $args) @@ -207,6 +209,7 @@ public static function formatMember($name) /** + * @param string * @return string */ public static function formatDocComment($content) @@ -222,6 +225,7 @@ public static function formatDocComment($content) /** + * @param string * @return string */ public static function unformatDocComment($comment) @@ -239,7 +243,11 @@ public static function isIdentifier($value) } - /** @internal */ + /** + * @param string + * @return object + * @internal + */ public static function createObject($class, array $props) { return unserialize('O' . substr(serialize((string) $class), 1, -1) . substr(serialize($props), 1)); diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 62afe994..b136430d 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -13,7 +13,7 @@ /** * Method or function description. * - * @property string $body + * @property string|FALSE $body */ class Method extends Member { @@ -52,6 +52,7 @@ class Method extends Member /** + * @param \ReflectionFunctionAbstract|callable * @return static */ public static function from($from) @@ -177,6 +178,7 @@ public function addUse($name) /** + * @param string|FALSE * @return static */ public function setBody($code, array $args = NULL) @@ -187,7 +189,7 @@ public function setBody($code, array $args = NULL) /** - * @return string + * @return string|FALSE */ public function getBody() { @@ -196,6 +198,7 @@ public function getBody() /** + * @param string * @return static */ public function addBody($code, array $args = NULL) diff --git a/src/PhpGenerator/PhpLiteral.php b/src/PhpGenerator/PhpLiteral.php index 1bf8d000..d38bf008 100644 --- a/src/PhpGenerator/PhpLiteral.php +++ b/src/PhpGenerator/PhpLiteral.php @@ -17,6 +17,9 @@ class PhpLiteral private $value; + /** + * @param string + */ public function __construct($value) { $this->value = (string) $value; diff --git a/src/PhpGenerator/PhpNamespace.php b/src/PhpGenerator/PhpNamespace.php index 5487555c..0cc2c6e7 100644 --- a/src/PhpGenerator/PhpNamespace.php +++ b/src/PhpGenerator/PhpNamespace.php @@ -37,6 +37,9 @@ class PhpNamespace private $classes = []; + /** + * @param string|NULL + */ public function __construct($name = NULL) { $this->setName($name); From 827394f70d078b9f0ad3901a40937551e4f5a3c9 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 22 Jan 2017 13:51:29 +0100 Subject: [PATCH 02/16] tests: new one --- tests/PhpGenerator/Factory.php7.phpt | 19 +++++++++++++++++++ tests/PhpGenerator/Helpers.format.phpt | 3 --- tests/PhpGenerator/Helpers.isIdentifier.phpt | 13 +++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/PhpGenerator/Factory.php7.phpt create mode 100644 tests/PhpGenerator/Helpers.isIdentifier.phpt diff --git a/tests/PhpGenerator/Factory.php7.phpt b/tests/PhpGenerator/Factory.php7.phpt new file mode 100644 index 00000000..6f0b2060 --- /dev/null +++ b/tests/PhpGenerator/Factory.php7.phpt @@ -0,0 +1,19 @@ +fromClassReflection(new ReflectionClass(new class {})); +Assert::type(Nette\PhpGenerator\ClassType::class, $res); +Assert::null($res->getName()); diff --git a/tests/PhpGenerator/Helpers.format.phpt b/tests/PhpGenerator/Helpers.format.phpt index 3382cd7f..d08b5e2a 100644 --- a/tests/PhpGenerator/Helpers.format.phpt +++ b/tests/PhpGenerator/Helpers.format.phpt @@ -38,6 +38,3 @@ Assert::same('$obj->{\' \'} = 2', Helpers::formatArgs('$obj->? = ?', [' ', 2])); Assert::same('Item', Helpers::formatMember('Item')); Assert::same("{'0Item'}", Helpers::formatMember('0Item')); - -Assert::true(Helpers::isIdentifier('Item')); -Assert::false(Helpers::isIdentifier('0Item')); diff --git a/tests/PhpGenerator/Helpers.isIdentifier.phpt b/tests/PhpGenerator/Helpers.isIdentifier.phpt new file mode 100644 index 00000000..b7300876 --- /dev/null +++ b/tests/PhpGenerator/Helpers.isIdentifier.phpt @@ -0,0 +1,13 @@ + Date: Sun, 22 Jan 2017 13:23:44 +0100 Subject: [PATCH 03/16] refactoring --- composer.json | 2 +- src/PhpGenerator/ClassType.php | 4 ++-- src/PhpGenerator/Factory.php | 10 +++------- src/PhpGenerator/Method.php | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 005dd266..323c6608 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": ">=5.6.0", - "nette/utils": "~2.4" + "nette/utils": "^2.4.2" }, "require-dev": { "nette/tester": "~2.0", diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index c20d30e1..641b041d 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -226,7 +226,7 @@ public function isAbstract() */ public function setExtends($types) { - if (!is_string($types) && !(is_array($types) && array_filter($types, 'is_string') === $types)) { + if (!is_string($types) && !(is_array($types) && Nette\Utils\Arrays::every($types, 'is_string'))) { throw new Nette\InvalidArgumentException('Argument must be string or string[].'); } $this->extends = $types; @@ -535,7 +535,7 @@ public function addMethod($name) { $method = (new Method($name))->setNamespace($this->namespace); if ($this->type === 'interface') { - $method->setVisibility(NULL)->setBody(FALSE); + $method->setBody(FALSE); } else { $method->setVisibility('public'); } diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 13b59adf..e98e3de2 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -39,13 +39,13 @@ public function fromClassReflection(\ReflectionClass $from) $props = $methods = []; foreach ($from->getProperties() as $prop) { if ($prop->isDefault() && $prop->getDeclaringClass()->getName() === $from->getName()) { - $props[$prop->getName()] = $this->fromPropertyReflection($prop); + $props[] = $this->fromPropertyReflection($prop); } } $class->setProperties($props); foreach ($from->getMethods() as $method) { if ($method->getDeclaringClass()->getName() === $from->getName()) { - $methods[$method->getName()] = $this->fromFunctionReflection($method)->setNamespace($class->getNamespace()); + $methods[] = $this->fromFunctionReflection($method)->setNamespace($class->getNamespace()); } } $class->setMethods($methods); @@ -59,11 +59,7 @@ public function fromClassReflection(\ReflectionClass $from) public function fromFunctionReflection(\ReflectionFunctionAbstract $from) { $method = new Method($from->isClosure() ? NULL : $from->getName()); - $params = []; - foreach ($from->getParameters() as $param) { - $params[$param->getName()] = $this->fromParameterReflection($param); - } - $method->setParameters($params); + $method->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters())); if ($from instanceof \ReflectionMethod) { $isInterface = $from->getDeclaringClass()->isInterface(); $method->setStatic($from->isStatic()); diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index b136430d..f165109c 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -20,7 +20,7 @@ class Method extends Member /** @var array of name => Parameter */ private $parameters = []; - /** @var array of name => bool */ + /** @var Parameter[] */ private $uses = []; /** @var string|FALSE */ From ac5bc5e520b6b84e08759539138c10c3d970417f Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 25 Jan 2017 02:50:33 +0100 Subject: [PATCH 04/16] composer: accepts nette 3.0 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 323c6608..2e5f1d38 100644 --- a/composer.json +++ b/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": ">=5.6.0", - "nette/utils": "^2.4.2" + "nette/utils": "^2.4.2 || ~3.0.0" }, "require-dev": { - "nette/tester": "~2.0", + "nette/tester": "^2.0", "tracy/tracy": "^2.3" }, "conflict": { From 320a86409e2c445c8d210e7caa050957522aba68 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 22 Feb 2017 18:37:25 +0100 Subject: [PATCH 05/16] opened 2.6-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2e5f1d38..939aea9d 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } } } From 81b293742846533fd8244bc969e92d29d3bcc058 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 23 Feb 2017 13:48:16 +0100 Subject: [PATCH 06/16] ClassType, Method::from() silently deprecated support for reflection objects --- src/PhpGenerator/ClassType.php | 6 +++--- src/PhpGenerator/Method.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index 641b041d..be2cca6b 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -65,13 +65,13 @@ class ClassType /** - * @param \ReflectionClass|string + * @param string|object * @return static */ - public static function from($from) + public static function from($class) { return (new Factory)->fromClassReflection( - $from instanceof \ReflectionClass ? $from : new \ReflectionClass($from) + $class instanceof \ReflectionClass ? $class : new \ReflectionClass($class) ); } diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index f165109c..787f7b6a 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -52,13 +52,13 @@ class Method extends Member /** - * @param \ReflectionFunctionAbstract|callable + * @param callable * @return static */ - public static function from($from) + public static function from($method) { return (new Factory)->fromFunctionReflection( - $from instanceof \ReflectionFunctionAbstract ? $from : Nette\Utils\Callback::toReflection($from) + $method instanceof \ReflectionFunctionAbstract ? $method : Nette\Utils\Callback::toReflection($method) ); } From e58789dbf12958faa44a71642329d5fd7b13b14d Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 23 Feb 2017 02:21:30 +0100 Subject: [PATCH 07/16] refactoring: transformed to traits, removed Member --- src/PhpGenerator/ClassType.php | 59 +----- src/PhpGenerator/Constant.php | 7 +- src/PhpGenerator/Method.php | 187 ++-------------- src/PhpGenerator/Parameter.php | 30 +-- src/PhpGenerator/PhpFile.php | 59 +----- src/PhpGenerator/Property.php | 7 +- .../{Member.php => Traits/CommentAware.php} | 65 +----- src/PhpGenerator/Traits/FunctionLike.php | 199 ++++++++++++++++++ src/PhpGenerator/Traits/NameAware.php | 45 ++++ src/PhpGenerator/Traits/VisibilityAware.php | 44 ++++ 10 files changed, 318 insertions(+), 384 deletions(-) rename src/PhpGenerator/{Member.php => Traits/CommentAware.php} (55%) create mode 100644 src/PhpGenerator/Traits/FunctionLike.php create mode 100644 src/PhpGenerator/Traits/NameAware.php create mode 100644 src/PhpGenerator/Traits/VisibilityAware.php diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index be2cca6b..f71377a4 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -20,6 +20,7 @@ class ClassType { use Nette\SmartObject; + use Traits\CommentAware; const TYPE_CLASS = 'class'; @@ -51,9 +52,6 @@ class ClassType /** @var string[] */ private $traits = []; - /** @var string|NULL */ - private $comment; - /** @var Constant[] name => Constant */ private $consts = []; @@ -317,61 +315,6 @@ public function addTrait($trait) } - /** - * @param string|NULL - * @return static - */ - public function setComment($val) - { - $this->comment = $val ? (string) $val : NULL; - return $this; - } - - - /** - * @return string|NULL - */ - public function getComment() - { - return $this->comment; - } - - - /** - * @param string - * @return static - */ - public function addComment($val) - { - $this->comment .= $this->comment ? "\n$val" : $val; - return $this; - } - - - /** @deprecated */ - public function setDocuments(array $s) - { - trigger_error(__METHOD__ . '() is deprecated, use similar setComment()', E_USER_DEPRECATED); - return $this->setComment(implode("\n", $s)); - } - - - /** @deprecated */ - public function getDocuments() - { - trigger_error(__METHOD__ . '() is deprecated, use similar getComment()', E_USER_DEPRECATED); - return $this->comment ? [$this->comment] : []; - } - - - /** @deprecated */ - public function addDocument($s) - { - trigger_error(__METHOD__ . '() is deprecated, use addComment()', E_USER_DEPRECATED); - return $this->addComment($s); - } - - /** * @deprecated use setConstants() * @return static diff --git a/src/PhpGenerator/Constant.php b/src/PhpGenerator/Constant.php index 75782f6c..86b5ad83 100644 --- a/src/PhpGenerator/Constant.php +++ b/src/PhpGenerator/Constant.php @@ -13,8 +13,13 @@ /** * Class constant. */ -class Constant extends Member +class Constant { + use Nette\SmartObject; + use Traits\NameAware; + use Traits\VisibilityAware; + use Traits\CommentAware; + /** @var mixed */ private $value; diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 787f7b6a..6a20b5ca 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -15,10 +15,13 @@ * * @property string|FALSE $body */ -class Method extends Member +class Method { - /** @var array of name => Parameter */ - private $parameters = []; + use Nette\SmartObject; + use Traits\FunctionLike; + use Traits\NameAware; + use Traits\VisibilityAware; + use Traits\CommentAware; /** @var Parameter[] */ private $uses = []; @@ -35,21 +38,6 @@ class Method extends Member /** @var bool */ private $abstract = FALSE; - /** @var bool */ - private $returnReference = FALSE; - - /** @var bool */ - private $variadic = FALSE; - - /** @var PhpNamespace|NULL */ - private $namespace; - - /** @var string|NULL */ - private $returnType; - - /** @var bool */ - private $returnNullable; - /** * @param callable @@ -63,89 +51,28 @@ public static function from($method) } - /** - * @param string|NULL - */ - public function __construct($name = NULL) - { - $this->setName($name); - } - - /** * @return string PHP code */ public function __toString() { - $parameters = []; - foreach ($this->parameters as $param) { - $variadic = $this->variadic && $param === end($this->parameters); - $hint = $param->getTypeHint(); - $parameters[] = ($hint ? ($param->isNullable() ? '?' : '') . ($this->namespace ? $this->namespace->unresolveName($hint) : $hint) . ' ' : '') - . ($param->isReference() ? '&' : '') - . ($variadic ? '...' : '') - . '$' . $param->getName() - . ($param->hasDefaultValue() && !$variadic ? ' = ' . Helpers::dump($param->defaultValue) : ''); - } $uses = []; foreach ($this->uses as $param) { $uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName(); } - - return Helpers::formatDocComment($this->getComment() . "\n") + return Helpers::formatDocComment($this->comment . "\n") . ($this->abstract ? 'abstract ' : '') . ($this->final ? 'final ' : '') - . ($this->getVisibility() ? $this->getVisibility() . ' ' : '') + . ($this->visibility ? $this->visibility . ' ' : '') . ($this->static ? 'static ' : '') . 'function ' . ($this->returnReference ? '&' : '') - . $this->getName() - . '(' . implode(', ', $parameters) . ')' + . $this->name + . $this->parametersToString() . ($this->uses ? ' use (' . implode(', ', $uses) . ')' : '') - . ($this->returnType ? ': ' . ($this->returnNullable ? '?' : '') - . ($this->namespace ? $this->namespace->unresolveName($this->returnType) : $this->returnType) : '') + . $this->returnTypeToString() . ($this->abstract || $this->body === FALSE ? ';' - : ($this->getName() ? "\n" : ' ') . "{\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}'); - } - - - /** - * @param Parameter[] - * @return static - */ - public function setParameters(array $val) - { - $this->parameters = []; - foreach ($val as $v) { - if (!$v instanceof Parameter) { - throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Parameter[].'); - } - $this->parameters[$v->getName()] = $v; - } - return $this; - } - - - /** - * @return Parameter[] - */ - public function getParameters() - { - return $this->parameters; - } - - - /** - * @param string without $ - * @return Parameter - */ - public function addParameter($name, $defaultValue = NULL) - { - $param = new Parameter($name); - if (func_num_args() > 1) { - $param->setOptional(TRUE)->setDefaultValue($defaultValue); - } - return $this->parameters[$name] = $param; + : ($this->name ? "\n" : ' ') . "{\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}'); } @@ -267,94 +194,4 @@ public function isAbstract() return $this->abstract; } - - /** - * @param bool - * @return static - */ - public function setReturnReference($val) - { - $this->returnReference = (bool) $val; - return $this; - } - - - /** - * @return bool - */ - public function getReturnReference() - { - return $this->returnReference; - } - - - /** - * @param bool - * @return static - */ - public function setReturnNullable($val) - { - $this->returnNullable = (bool) $val; - return $this; - } - - - /** - * @return bool - */ - public function getReturnNullable() - { - return $this->returnNullable; - } - - - /** - * @param bool - * @return static - */ - public function setVariadic($val) - { - $this->variadic = (bool) $val; - return $this; - } - - - /** - * @return bool - */ - public function isVariadic() - { - return $this->variadic; - } - - - /** - * @return static - */ - public function setNamespace(PhpNamespace $val = NULL) - { - $this->namespace = $val; - return $this; - } - - - /** - * @param string|NULL - * @return static - */ - public function setReturnType($val) - { - $this->returnType = $val ? (string) $val : NULL; - return $this; - } - - - /** - * @return string|NULL - */ - public function getReturnType() - { - return $this->returnType; - } - } diff --git a/src/PhpGenerator/Parameter.php b/src/PhpGenerator/Parameter.php index 2c090f65..50e60d86 100644 --- a/src/PhpGenerator/Parameter.php +++ b/src/PhpGenerator/Parameter.php @@ -16,9 +16,7 @@ class Parameter { use Nette\SmartObject; - - /** @var string */ - private $name = ''; + use Traits\NameAware; /** @var bool */ private $reference = FALSE; @@ -46,32 +44,6 @@ public static function from(\ReflectionParameter $from) } - /** - * @param string without $ - */ - public function __construct($name = '') - { - $this->setName($name); - } - - - /** @deprecated */ - public function setName($name) - { - $this->name = (string) $name; - return $this; - } - - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** * @param bool * @return static diff --git a/src/PhpGenerator/PhpFile.php b/src/PhpGenerator/PhpFile.php index 007fc382..4fd1b28b 100644 --- a/src/PhpGenerator/PhpFile.php +++ b/src/PhpGenerator/PhpFile.php @@ -22,69 +22,12 @@ class PhpFile { use Nette\SmartObject; - - /** @var string|NULL */ - private $comment; + use Traits\CommentAware; /** @var PhpNamespace[] */ private $namespaces = []; - /** - * @param string|NULL - * @return static - */ - public function setComment($val) - { - $this->comment = $val ? (string) $val : NULL; - return $this; - } - - - /** - * @return string|NULL - */ - public function getComment() - { - return $this->comment; - } - - - /** - * @param string - * @return static - */ - public function addComment($val) - { - $this->comment .= $this->comment ? "\n$val" : $val; - return $this; - } - - - /** @deprecated */ - public function setDocuments(array $s) - { - trigger_error(__METHOD__ . '() is deprecated, use similar setComment()', E_USER_DEPRECATED); - return $this->setComment(implode("\n", $s)); - } - - - /** @deprecated */ - public function getDocuments() - { - trigger_error(__METHOD__ . '() is deprecated, use similar getComment()', E_USER_DEPRECATED); - return $this->comment ? [$this->comment] : []; - } - - - /** @deprecated */ - public function addDocument($s) - { - trigger_error(__METHOD__ . '() is deprecated, use addComment()', E_USER_DEPRECATED); - return $this->addComment($s); - } - - /** * @param string * @return ClassType diff --git a/src/PhpGenerator/Property.php b/src/PhpGenerator/Property.php index f8c9e531..552f04d8 100644 --- a/src/PhpGenerator/Property.php +++ b/src/PhpGenerator/Property.php @@ -13,8 +13,13 @@ /** * Class property description. */ -class Property extends Member +class Property { + use Nette\SmartObject; + use Traits\NameAware; + use Traits\VisibilityAware; + use Traits\CommentAware; + /** @var mixed */ public $value; diff --git a/src/PhpGenerator/Member.php b/src/PhpGenerator/Traits/CommentAware.php similarity index 55% rename from src/PhpGenerator/Member.php rename to src/PhpGenerator/Traits/CommentAware.php index e1e39186..1c34bc88 100644 --- a/src/PhpGenerator/Member.php +++ b/src/PhpGenerator/Traits/CommentAware.php @@ -5,77 +5,18 @@ * Copyright (c) 2004 David Grudl (https://davidgrudl.com) */ -namespace Nette\PhpGenerator; - -use Nette; +namespace Nette\PhpGenerator\Traits; /** - * Class member. + * @internal */ -abstract class Member +trait CommentAware { - use Nette\SmartObject; - - /** @var string */ - private $name; - - /** @var string|NULL public|protected|private */ - private $visibility; - /** @var string|NULL */ private $comment; - /** - * @param string - */ - public function __construct($name = '') - { - $this->setName($name); - } - - - /** @deprecated */ - public function setName($name) - { - $this->name = (string) $name; - return $this; - } - - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - - /** - * @param string|NULL public|protected|private - * @return static - */ - public function setVisibility($val) - { - if (!in_array($val, ['public', 'protected', 'private', NULL], TRUE)) { - throw new Nette\InvalidArgumentException('Argument must be public|protected|private.'); - } - $this->visibility = $val; - return $this; - } - - - /** - * @return string|NULL - */ - public function getVisibility() - { - return $this->visibility; - } - - /** * @param string|NULL * @return static diff --git a/src/PhpGenerator/Traits/FunctionLike.php b/src/PhpGenerator/Traits/FunctionLike.php new file mode 100644 index 00000000..d3fed4ba --- /dev/null +++ b/src/PhpGenerator/Traits/FunctionLike.php @@ -0,0 +1,199 @@ + Parameter */ + private $parameters = []; + + /** @var bool */ + private $variadic = FALSE; + + /** @var string|NULL */ + private $returnType; + + /** @var bool */ + private $returnReference = FALSE; + + /** @var bool */ + private $returnNullable; + + /** @var PhpNamespace|NULL */ + private $namespace; + + + /** + * @param Parameter[] + * @return static + */ + public function setParameters(array $val) + { + $this->parameters = []; + foreach ($val as $v) { + if (!$v instanceof Parameter) { + throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Parameter[].'); + } + $this->parameters[$v->getName()] = $v; + } + return $this; + } + + + /** + * @return Parameter[] + */ + public function getParameters() + { + return $this->parameters; + } + + + /** + * @param string without $ + * @return Parameter + */ + public function addParameter($name, $defaultValue = NULL) + { + $param = new Parameter($name); + if (func_num_args() > 1) { + $param->setOptional(TRUE)->setDefaultValue($defaultValue); + } + return $this->parameters[$name] = $param; + } + + + /** + * @param bool + * @return static + */ + public function setVariadic($val) + { + $this->variadic = (bool) $val; + return $this; + } + + + /** + * @return bool + */ + public function isVariadic() + { + return $this->variadic; + } + + + /** + * @param string|NULL + * @return static + */ + public function setReturnType($val) + { + $this->returnType = $val ? (string) $val : NULL; + return $this; + } + + + /** + * @return string|NULL + */ + public function getReturnType() + { + return $this->returnType; + } + + + /** + * @param bool + * @return static + */ + public function setReturnReference($val) + { + $this->returnReference = (bool) $val; + return $this; + } + + + /** + * @return bool + */ + public function getReturnReference() + { + return $this->returnReference; + } + + + /** + * @param bool + * @return static + */ + public function setReturnNullable($val) + { + $this->returnNullable = (bool) $val; + return $this; + } + + + /** + * @return bool + */ + public function getReturnNullable() + { + return $this->returnNullable; + } + + + /** + * @return static + */ + public function setNamespace(PhpNamespace $val = NULL) + { + $this->namespace = $val; + return $this; + } + + + /** + * @return string + */ + protected function parametersToString() + { + $params = []; + foreach ($this->parameters as $param) { + $variadic = $this->variadic && $param === end($this->parameters); + $hint = $param->getTypeHint(); + $params[] = ($hint ? ($param->isNullable() ? '?' : '') . ($this->namespace ? $this->namespace->unresolveName($hint) : $hint) . ' ' : '') + . ($param->isReference() ? '&' : '') + . ($variadic ? '...' : '') + . '$' . $param->getName() + . ($param->hasDefaultValue() && !$variadic ? ' = ' . Helpers::dump($param->defaultValue) : ''); + } + return '(' . implode(', ', $params) . ')'; + } + + + /** + * @return string + */ + protected function returnTypeToString() + { + return $this->returnType + ? ': ' . ($this->returnNullable ? '?' : '') . ($this->namespace ? $this->namespace->unresolveName($this->returnType) : $this->returnType) + : ''; + } + +} diff --git a/src/PhpGenerator/Traits/NameAware.php b/src/PhpGenerator/Traits/NameAware.php new file mode 100644 index 00000000..21e2f292 --- /dev/null +++ b/src/PhpGenerator/Traits/NameAware.php @@ -0,0 +1,45 @@ +setName($name); + } + + + /** @deprecated */ + public function setName($name) + { + $this->name = (string) $name; + return $this; + } + + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + +} diff --git a/src/PhpGenerator/Traits/VisibilityAware.php b/src/PhpGenerator/Traits/VisibilityAware.php new file mode 100644 index 00000000..649b986d --- /dev/null +++ b/src/PhpGenerator/Traits/VisibilityAware.php @@ -0,0 +1,44 @@ +visibility = $val; + return $this; + } + + + /** + * @return string|NULL + */ + public function getVisibility() + { + return $this->visibility; + } + +} From f5ead286ab95032ee85bec3cccc94343878673c2 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 22 Feb 2017 19:31:05 +0100 Subject: [PATCH 08/16] Method split to GlobalFunction & Closure (BC break) BC break: Method cannot render closure --- src/PhpGenerator/Closure.php | 82 +++++++++++++++++++ src/PhpGenerator/Factory.php | 8 +- src/PhpGenerator/GlobalFunction.php | 49 +++++++++++ src/PhpGenerator/Method.php | 69 ++++------------ src/PhpGenerator/Traits/FunctionLike.php | 34 ++++++++ .../{Method.function.phpt => Closure.phpt} | 30 +------ tests/PhpGenerator/Factory.phpt | 5 +- tests/PhpGenerator/GlobalFunction.phpt | 21 +++++ 8 files changed, 214 insertions(+), 84 deletions(-) create mode 100644 src/PhpGenerator/Closure.php create mode 100644 src/PhpGenerator/GlobalFunction.php rename tests/PhpGenerator/{Method.function.phpt => Closure.phpt} (53%) create mode 100644 tests/PhpGenerator/GlobalFunction.phpt diff --git a/src/PhpGenerator/Closure.php b/src/PhpGenerator/Closure.php new file mode 100644 index 00000000..81b3da8e --- /dev/null +++ b/src/PhpGenerator/Closure.php @@ -0,0 +1,82 @@ +fromFunctionReflection(new \ReflectionFunction($closure)); + } + + + /** + * @return string PHP code + */ + public function __toString() + { + $uses = []; + foreach ($this->uses as $param) { + $uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName(); + } + return 'function ' + . ($this->returnReference ? '&' : '') + . $this->parametersToString() + . ($this->uses ? ' use (' . implode(', ', $uses) . ')' : '') + . $this->returnTypeToString() + . " {\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}'; + } + + + /** + * @param Parameter[] + * @return static + */ + public function setUses(array $uses) + { + $this->uses = $uses; + return $this; + } + + + /** + * @return array + */ + public function getUses() + { + return $this->uses; + } + + + /** + * @return Parameter + */ + public function addUse($name) + { + return $this->uses[] = new Parameter($name); + } + +} diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index e98e3de2..cf6cd193 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -58,7 +58,9 @@ public function fromClassReflection(\ReflectionClass $from) */ public function fromFunctionReflection(\ReflectionFunctionAbstract $from) { - $method = new Method($from->isClosure() ? NULL : $from->getName()); + $method = $from instanceof \ReflectionMethod + ? new Method($from->getName()) + : ($from->isClosure() ? new Closure : new GlobalFunction($from->getName())); $method->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters())); if ($from instanceof \ReflectionMethod) { $isInterface = $from->getDeclaringClass()->isInterface(); @@ -70,7 +72,9 @@ public function fromFunctionReflection(\ReflectionFunctionAbstract $from) } $method->setReturnReference($from->returnsReference()); $method->setVariadic($from->isVariadic()); - $method->setComment(Helpers::unformatDocComment($from->getDocComment())); + if (!$from->isClosure()) { + $method->setComment(Helpers::unformatDocComment($from->getDocComment())); + } if (PHP_VERSION_ID >= 70000 && $from->hasReturnType()) { $method->setReturnType((string) $from->getReturnType()); $method->setReturnNullable($from->getReturnType()->allowsNull()); diff --git a/src/PhpGenerator/GlobalFunction.php b/src/PhpGenerator/GlobalFunction.php new file mode 100644 index 00000000..35e2da00 --- /dev/null +++ b/src/PhpGenerator/GlobalFunction.php @@ -0,0 +1,49 @@ +fromFunctionReflection(new \ReflectionFunction($function)); + } + + + /** + * @return string PHP code + */ + public function __toString() + { + return Helpers::formatDocComment($this->comment . "\n") + . 'function ' + . ($this->returnReference ? '&' : '') + . $this->name + . $this->parametersToString() + . $this->returnTypeToString() + . "\n{\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}'; + } + +} diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 6a20b5ca..bd35b1bf 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -11,7 +11,7 @@ /** - * Method or function description. + * Class method. * * @property string|FALSE $body */ @@ -23,12 +23,6 @@ class Method use Traits\VisibilityAware; use Traits\CommentAware; - /** @var Parameter[] */ - private $uses = []; - - /** @var string|FALSE */ - private $body = ''; - /** @var bool */ private $static = FALSE; @@ -51,15 +45,23 @@ public static function from($method) } + /** + * @param string + */ + public function __construct($name = NULL) + { + if ($name === NULL) { + throw new Nette\DeprecatedException('For closures use Nette\PhpGenerator\GlobalFunction instead of Nette\PhpGenerator\Method.'); + } + $this->setName($name); + } + + /** * @return string PHP code */ public function __toString() { - $uses = []; - foreach ($this->uses as $param) { - $uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName(); - } return Helpers::formatDocComment($this->comment . "\n") . ($this->abstract ? 'abstract ' : '') . ($this->final ? 'final ' : '') @@ -69,38 +71,10 @@ public function __toString() . ($this->returnReference ? '&' : '') . $this->name . $this->parametersToString() - . ($this->uses ? ' use (' . implode(', ', $uses) . ')' : '') . $this->returnTypeToString() - . ($this->abstract || $this->body === FALSE ? ';' - : ($this->name ? "\n" : ' ') . "{\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}'); - } - - - /** - * @return static - */ - public function setUses(array $val) - { - $this->uses = $val; - return $this; - } - - - /** - * @return array - */ - public function getUses() - { - return $this->uses; - } - - - /** - * @return Parameter - */ - public function addUse($name) - { - return $this->uses[] = new Parameter($name); + . ($this->abstract || $this->body === FALSE + ? ';' + : "\n{\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}'); } @@ -124,17 +98,6 @@ public function getBody() } - /** - * @param string - * @return static - */ - public function addBody($code, array $args = NULL) - { - $this->body .= ($args === NULL ? $code : Helpers::formatArgs($code, $args)) . "\n"; - return $this; - } - - /** * @param bool * @return static diff --git a/src/PhpGenerator/Traits/FunctionLike.php b/src/PhpGenerator/Traits/FunctionLike.php index d3fed4ba..a84f0d04 100644 --- a/src/PhpGenerator/Traits/FunctionLike.php +++ b/src/PhpGenerator/Traits/FunctionLike.php @@ -18,6 +18,9 @@ */ trait FunctionLike { + /** @var string */ + private $body = ''; + /** @var array of name => Parameter */ private $parameters = []; @@ -37,6 +40,37 @@ trait FunctionLike private $namespace; + /** + * @param string + * @return static + */ + public function setBody($code, array $args = NULL) + { + $this->body = $args === NULL ? $code : Helpers::formatArgs($code, $args); + return $this; + } + + + /** + * @return string + */ + public function getBody() + { + return $this->body; + } + + + /** + * @param string + * @return static + */ + public function addBody($code, array $args = NULL) + { + $this->body .= ($args === NULL ? $code : Helpers::formatArgs($code, $args)) . "\n"; + return $this; + } + + /** * @param Parameter[] * @return static diff --git a/tests/PhpGenerator/Method.function.phpt b/tests/PhpGenerator/Closure.phpt similarity index 53% rename from tests/PhpGenerator/Method.function.phpt rename to tests/PhpGenerator/Closure.phpt index 1967bb93..f2886f22 100644 --- a/tests/PhpGenerator/Method.function.phpt +++ b/tests/PhpGenerator/Closure.phpt @@ -1,17 +1,13 @@ setReturnReference(TRUE) ->setBody('return $a + $b;'); @@ -28,26 +24,8 @@ Assert::match( }', (string) $function); -/** closure */ $closure = function (stdClass $a, $b = NULL) {}; -$function = Method::from($closure); -Assert::match( -'/** - * closure - */ -function (stdClass $a, $b = NULL) { -}', (string) $function); - - -/** global */ -function func(stdClass $a, $b = NULL) { -}; - -$function = Method::from('func'); +$function = Closure::from($closure); Assert::match( -'/** - * global - */ -function func(stdClass $a, $b = NULL) -{ +'function (stdClass $a, $b = NULL) { }', (string) $function); diff --git a/tests/PhpGenerator/Factory.phpt b/tests/PhpGenerator/Factory.phpt index c0c48fdb..f1b530a4 100644 --- a/tests/PhpGenerator/Factory.phpt +++ b/tests/PhpGenerator/Factory.phpt @@ -24,10 +24,9 @@ Assert::same('getName', $res->getName()); $res = $factory->fromFunctionReflection(new \ReflectionFunction('trim')); -Assert::type(Nette\PhpGenerator\Method::class, $res); +Assert::type(Nette\PhpGenerator\GlobalFunction::class, $res); Assert::same('trim', $res->getName()); $res = $factory->fromFunctionReflection(new \ReflectionFunction(function () {})); -Assert::type(Nette\PhpGenerator\Method::class, $res); -Assert::same('', $res->getName()); +Assert::type(Nette\PhpGenerator\Closure::class, $res); diff --git a/tests/PhpGenerator/GlobalFunction.phpt b/tests/PhpGenerator/GlobalFunction.phpt new file mode 100644 index 00000000..cc9e47c7 --- /dev/null +++ b/tests/PhpGenerator/GlobalFunction.phpt @@ -0,0 +1,21 @@ + Date: Thu, 23 Feb 2017 00:31:37 +0100 Subject: [PATCH 09/16] added Factory::fromMethodReflection() --- src/PhpGenerator/Factory.php | 46 +++++++++++++++++++++------------ src/PhpGenerator/Method.php | 11 +++++--- tests/PhpGenerator/Factory.phpt | 2 +- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index cf6cd193..dc98ece2 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -45,7 +45,7 @@ public function fromClassReflection(\ReflectionClass $from) $class->setProperties($props); foreach ($from->getMethods() as $method) { if ($method->getDeclaringClass()->getName() === $from->getName()) { - $methods[] = $this->fromFunctionReflection($method)->setNamespace($class->getNamespace()); + $methods[] = $this->fromMethodReflection($method)->setNamespace($class->getNamespace()); } } $class->setMethods($methods); @@ -56,25 +56,19 @@ public function fromClassReflection(\ReflectionClass $from) /** * @return Method */ - public function fromFunctionReflection(\ReflectionFunctionAbstract $from) + public function fromMethodReflection(\ReflectionMethod $from) { - $method = $from instanceof \ReflectionMethod - ? new Method($from->getName()) - : ($from->isClosure() ? new Closure : new GlobalFunction($from->getName())); + $method = new Method($from->getName()); $method->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters())); - if ($from instanceof \ReflectionMethod) { - $isInterface = $from->getDeclaringClass()->isInterface(); - $method->setStatic($from->isStatic()); - $method->setVisibility($from->isPrivate() ? 'private' : ($from->isProtected() ? 'protected' : ($isInterface ? NULL : 'public'))); - $method->setFinal($from->isFinal()); - $method->setAbstract($from->isAbstract() && !$isInterface); - $method->setBody($from->isAbstract() ? FALSE : ''); - } + $method->setStatic($from->isStatic()); + $isInterface = $from->getDeclaringClass()->isInterface(); + $method->setVisibility($from->isPrivate() ? 'private' : ($from->isProtected() ? 'protected' : ($isInterface ? NULL : 'public'))); + $method->setFinal($from->isFinal()); + $method->setAbstract($from->isAbstract() && !$isInterface); + $method->setBody($from->isAbstract() ? FALSE : ''); $method->setReturnReference($from->returnsReference()); $method->setVariadic($from->isVariadic()); - if (!$from->isClosure()) { - $method->setComment(Helpers::unformatDocComment($from->getDocComment())); - } + $method->setComment(Helpers::unformatDocComment($from->getDocComment())); if (PHP_VERSION_ID >= 70000 && $from->hasReturnType()) { $method->setReturnType((string) $from->getReturnType()); $method->setReturnNullable($from->getReturnType()->allowsNull()); @@ -83,6 +77,26 @@ public function fromFunctionReflection(\ReflectionFunctionAbstract $from) } + /** + * @return GlobalFunction|Closure + */ + public function fromFunctionReflection(\ReflectionFunction $from) + { + $function = $from->isClosure() ? new Closure : new GlobalFunction($from->getName()); + $function->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters())); + $function->setReturnReference($from->returnsReference()); + $function->setVariadic($from->isVariadic()); + if (!$from->isClosure()) { + $function->setComment(Helpers::unformatDocComment($from->getDocComment())); + } + if (PHP_VERSION_ID >= 70000 && $from->hasReturnType()) { + $function->setReturnType((string) $from->getReturnType()); + $function->setReturnNullable($from->getReturnType()->allowsNull()); + } + return $function; + } + + /** * @return Parameter */ diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index bd35b1bf..612f70d1 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -39,9 +39,12 @@ class Method */ public static function from($method) { - return (new Factory)->fromFunctionReflection( - $method instanceof \ReflectionFunctionAbstract ? $method : Nette\Utils\Callback::toReflection($method) - ); + $method = $method instanceof \ReflectionFunctionAbstract ? $method : Nette\Utils\Callback::toReflection($method); + if ($method instanceof \ReflectionFunction) { + trigger_error('For global functions or closures use Nette\PhpGenerator\GlobalFunction or Nette\PhpGenerator\Closure.', E_USER_DEPRECATED); + return (new Factory)->fromFunctionReflection($method); + } + return (new Factory)->fromMethodReflection($method); } @@ -51,7 +54,7 @@ public static function from($method) public function __construct($name = NULL) { if ($name === NULL) { - throw new Nette\DeprecatedException('For closures use Nette\PhpGenerator\GlobalFunction instead of Nette\PhpGenerator\Method.'); + throw new Nette\DeprecatedException('For closures use Nette\PhpGenerator\Closure instead of Nette\PhpGenerator\Method.'); } $this->setName($name); } diff --git a/tests/PhpGenerator/Factory.phpt b/tests/PhpGenerator/Factory.phpt index f1b530a4..2c0866d8 100644 --- a/tests/PhpGenerator/Factory.phpt +++ b/tests/PhpGenerator/Factory.phpt @@ -18,7 +18,7 @@ Assert::type(Nette\PhpGenerator\ClassType::class, $res); Assert::same('stdClass', $res->getName()); -$res = $factory->fromFunctionReflection(new \ReflectionMethod(ReflectionClass::class, 'getName')); +$res = $factory->fromMethodReflection(new \ReflectionMethod(ReflectionClass::class, 'getName')); Assert::type(Nette\PhpGenerator\Method::class, $res); Assert::same('getName', $res->getName()); From 392139ba6084e3f96c71ab5b8b6e7bd8af4a95ac Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 22 Feb 2017 16:01:46 +0100 Subject: [PATCH 10/16] name validation moved from setName() to __construct() --- src/PhpGenerator/Method.php | 4 ++-- src/PhpGenerator/PhpNamespace.php | 4 ++-- src/PhpGenerator/Traits/NameAware.php | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 612f70d1..938f566c 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -51,12 +51,12 @@ public static function from($method) /** * @param string */ - public function __construct($name = NULL) + public function __construct($name) { if ($name === NULL) { throw new Nette\DeprecatedException('For closures use Nette\PhpGenerator\Closure instead of Nette\PhpGenerator\Method.'); } - $this->setName($name); + $this->name = (string) $name; } diff --git a/src/PhpGenerator/PhpNamespace.php b/src/PhpGenerator/PhpNamespace.php index 0cc2c6e7..5b6e6510 100644 --- a/src/PhpGenerator/PhpNamespace.php +++ b/src/PhpGenerator/PhpNamespace.php @@ -42,14 +42,14 @@ class PhpNamespace */ public function __construct($name = NULL) { - $this->setName($name); + $this->name = (string) $name; } /** @deprecated */ public function setName($name) { - $this->name = (string) $name; + $this->__construct($name); return $this; } diff --git a/src/PhpGenerator/Traits/NameAware.php b/src/PhpGenerator/Traits/NameAware.php index 21e2f292..7904bbd3 100644 --- a/src/PhpGenerator/Traits/NameAware.php +++ b/src/PhpGenerator/Traits/NameAware.php @@ -20,16 +20,16 @@ trait NameAware /** * @param string */ - public function __construct($name = '') + public function __construct($name) { - $this->setName($name); + $this->name = (string) $name; } /** @deprecated */ public function setName($name) { - $this->name = (string) $name; + $this->__construct($name); return $this; } From 2ae5659e7cf8c3f22cd74ad190eee2f0c4c17396 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 21 Dec 2016 23:14:08 +0100 Subject: [PATCH 11/16] deprecated setName() & from() trigger warnings (BC break) --- src/PhpGenerator/Parameter.php | 1 + src/PhpGenerator/Property.php | 1 + src/PhpGenerator/Traits/NameAware.php | 1 + 3 files changed, 3 insertions(+) diff --git a/src/PhpGenerator/Parameter.php b/src/PhpGenerator/Parameter.php index 50e60d86..0f5a4e16 100644 --- a/src/PhpGenerator/Parameter.php +++ b/src/PhpGenerator/Parameter.php @@ -40,6 +40,7 @@ class Parameter */ public static function from(\ReflectionParameter $from) { + trigger_error(__METHOD__ . '() is deprecated, use Nette\PhpGenerator\Factory.', E_USER_DEPRECATED); return (new Factory)->fromParameterReflection($from); } diff --git a/src/PhpGenerator/Property.php b/src/PhpGenerator/Property.php index 552f04d8..4d57e247 100644 --- a/src/PhpGenerator/Property.php +++ b/src/PhpGenerator/Property.php @@ -33,6 +33,7 @@ class Property */ public static function from(\ReflectionProperty $from) { + trigger_error(__METHOD__ . '() is deprecated, use Nette\PhpGenerator\Factory.', E_USER_DEPRECATED); return (new Factory)->fromPropertyReflection($from); } diff --git a/src/PhpGenerator/Traits/NameAware.php b/src/PhpGenerator/Traits/NameAware.php index 7904bbd3..d0907c2c 100644 --- a/src/PhpGenerator/Traits/NameAware.php +++ b/src/PhpGenerator/Traits/NameAware.php @@ -29,6 +29,7 @@ public function __construct($name) /** @deprecated */ public function setName($name) { + trigger_error(__METHOD__ . '() is deprecated, use constructor.', E_USER_DEPRECATED); $this->__construct($name); return $this; } From ff01f24934a0ed17ae7a0afd1544b746e06675b9 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 22 Feb 2017 15:13:02 +0100 Subject: [PATCH 12/16] added Helpers::isNamespace --- src/PhpGenerator/Helpers.php | 9 +++++++++ tests/PhpGenerator/Helpers.isNamespace.phpt | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/PhpGenerator/Helpers.isNamespace.phpt diff --git a/src/PhpGenerator/Helpers.php b/src/PhpGenerator/Helpers.php index 53ddc939..c09fffbe 100644 --- a/src/PhpGenerator/Helpers.php +++ b/src/PhpGenerator/Helpers.php @@ -243,6 +243,15 @@ public static function isIdentifier($value) } + /** + * @return bool + */ + public static function isNamespace($value) + { + return is_string($value) && preg_match('#^' . Helpers::PHP_IDENT . '(\\\\' . Helpers::PHP_IDENT . ')*\z#', $value); + } + + /** * @param string * @return object diff --git a/tests/PhpGenerator/Helpers.isNamespace.phpt b/tests/PhpGenerator/Helpers.isNamespace.phpt new file mode 100644 index 00000000..4c0bacd6 --- /dev/null +++ b/tests/PhpGenerator/Helpers.isNamespace.phpt @@ -0,0 +1,17 @@ + Date: Wed, 22 Feb 2017 19:02:40 +0100 Subject: [PATCH 13/16] Checks whether names are valid [Closes #24] --- src/PhpGenerator/ClassType.php | 3 + src/PhpGenerator/Method.php | 4 +- src/PhpGenerator/PhpNamespace.php | 3 + src/PhpGenerator/Traits/NameAware.php | 7 +- tests/PhpGenerator/invalidNames.phpt | 147 ++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 tests/PhpGenerator/invalidNames.phpt diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index f71377a4..84a8f841 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -141,6 +141,9 @@ public function getNamespace() */ public function setName($name) { + if ($name !== NULL && !Helpers::isIdentifier($name)) { + throw new Nette\InvalidArgumentException("Value '$name' is not valid class name."); + } $this->name = $name; return $this; } diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 938f566c..707bb647 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -55,8 +55,10 @@ public function __construct($name) { if ($name === NULL) { throw new Nette\DeprecatedException('For closures use Nette\PhpGenerator\Closure instead of Nette\PhpGenerator\Method.'); + } elseif (!Helpers::isIdentifier($name)) { + throw new Nette\InvalidArgumentException("Value '$name' is not valid name."); } - $this->name = (string) $name; + $this->name = $name; } diff --git a/src/PhpGenerator/PhpNamespace.php b/src/PhpGenerator/PhpNamespace.php index 5b6e6510..b34d37c0 100644 --- a/src/PhpGenerator/PhpNamespace.php +++ b/src/PhpGenerator/PhpNamespace.php @@ -42,6 +42,9 @@ class PhpNamespace */ public function __construct($name = NULL) { + if ($name && !Helpers::isNamespace($name)) { + throw new Nette\InvalidArgumentException("Value '$name' is not valid name."); + } $this->name = (string) $name; } diff --git a/src/PhpGenerator/Traits/NameAware.php b/src/PhpGenerator/Traits/NameAware.php index d0907c2c..18a588dc 100644 --- a/src/PhpGenerator/Traits/NameAware.php +++ b/src/PhpGenerator/Traits/NameAware.php @@ -7,6 +7,8 @@ namespace Nette\PhpGenerator\Traits; +use Nette; + /** * @internal @@ -22,7 +24,10 @@ trait NameAware */ public function __construct($name) { - $this->name = (string) $name; + if (!Nette\PhpGenerator\Helpers::isIdentifier($name)) { + throw new Nette\InvalidArgumentException("Value '$name' is not valid name."); + } + $this->name = $name; } diff --git a/tests/PhpGenerator/invalidNames.phpt b/tests/PhpGenerator/invalidNames.phpt new file mode 100644 index 00000000..fea9335c --- /dev/null +++ b/tests/PhpGenerator/invalidNames.phpt @@ -0,0 +1,147 @@ + Date: Fri, 24 Feb 2017 19:51:08 +0100 Subject: [PATCH 14/16] PhpNamespace: recognizes 'void' and 'iterable' as built-in types --- src/PhpGenerator/PhpNamespace.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/PhpGenerator/PhpNamespace.php b/src/PhpGenerator/PhpNamespace.php index b34d37c0..00234dc9 100644 --- a/src/PhpGenerator/PhpNamespace.php +++ b/src/PhpGenerator/PhpNamespace.php @@ -24,6 +24,11 @@ class PhpNamespace { use Nette\SmartObject; + private static $keywords = [ + 'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, + 'callable' => 1, 'iterable' => 1, 'void' => 1, 'self' => 1, 'parent' => 1, + ]; + /** @var string */ private $name; @@ -139,7 +144,7 @@ public function getUses() */ public function unresolveName($name) { - if (in_array(strtolower($name), ['self', 'parent', 'array', 'callable', 'string', 'bool', 'float', 'int', ''], TRUE)) { + if (isset(self::$keywords[strtolower($name)]) || $name === '') { return $name; } $name = ltrim($name, '\\'); From 54af5adaeb14243707852d40d9272c43fae08245 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 24 Feb 2017 19:33:59 +0100 Subject: [PATCH 15/16] ClassType: added possibility to define trait resolution rules --- src/PhpGenerator/ClassType.php | 16 +++++++++++----- tests/PhpGenerator/ClassType.expect | 3 +++ tests/PhpGenerator/ClassType.phpt | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index 84a8f841..abefb645 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -89,6 +89,12 @@ public function __construct($name = NULL, PhpNamespace $namespace = NULL) */ public function __toString() { + $traits = []; + foreach ($this->traits as $trait => $resolutions) { + $traits[] = 'use ' . ($this->namespace ? $this->namespace->unresolveName($trait) : $trait) + . ($resolutions ? " {\n\t" . implode(";\n\t", $resolutions) . ";\n}" : ';'); + } + $consts = []; foreach ($this->consts as $const) { $consts[] = Helpers::formatDocComment($const->getComment()) @@ -117,7 +123,7 @@ public function __toString() . ($this->implements ? 'implements ' . implode(', ', $mapper($this->implements)) . ' ' : '') . ($this->name ? "\n" : '') . "{\n" . Strings::indent( - ($this->traits ? 'use ' . implode(";\nuse ", $mapper($this->traits)) . ";\n\n" : '') + ($this->traits ? implode("\n", $traits) . "\n\n" : '') . ($this->consts ? implode('', $consts) . "\n" : '') . ($this->properties ? implode("\n", $properties) . "\n" : '') . ($this->methods ? "\n" . implode("\n\n\n", $this->methods) . "\n\n" : ''), 1) @@ -293,7 +299,7 @@ public function addImplement($type) */ public function setTraits(array $traits) { - $this->traits = $traits; + $this->traits = array_fill_keys($traits, []); return $this; } @@ -303,7 +309,7 @@ public function setTraits(array $traits) */ public function getTraits() { - return $this->traits; + return array_keys($this->traits); } @@ -311,9 +317,9 @@ public function getTraits() * @param string * @return static */ - public function addTrait($trait) + public function addTrait($trait, array $resolutions = []) { - $this->traits[] = (string) $trait; + $this->traits[$trait] = $resolutions; return $this; } diff --git a/tests/PhpGenerator/ClassType.expect b/tests/PhpGenerator/ClassType.expect index cfe2e76d..cd6cbb97 100644 --- a/tests/PhpGenerator/ClassType.expect +++ b/tests/PhpGenerator/ClassType.expect @@ -7,6 +7,9 @@ abstract final class Example extends ParentClass implements IExample, IOne { use ObjectTrait; + use AnotherTrait { + sayHello as protected; + } const ROLE = 'admin'; const ACTIVE = FALSE; diff --git a/tests/PhpGenerator/ClassType.phpt b/tests/PhpGenerator/ClassType.phpt index 8584e472..a75fa3cf 100644 --- a/tests/PhpGenerator/ClassType.phpt +++ b/tests/PhpGenerator/ClassType.phpt @@ -20,6 +20,7 @@ $class ->addImplement('IExample') ->addImplement('IOne') ->addTrait('ObjectTrait') + ->addTrait('AnotherTrait', ['sayHello as protected']) ->addComment("Description of class.\nThis is example\n") ->addComment('@property-read Nette\Forms\Form $form') ->setConsts(['ROLE' => 'admin']) From eff05975fee1645471d4371b7a0a7acb62a25b15 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 24 Feb 2017 20:24:08 +0100 Subject: [PATCH 16/16] refactoring --- src/PhpGenerator/ClassType.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index abefb645..9ea46e33 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -23,9 +23,7 @@ class ClassType use Traits\CommentAware; const TYPE_CLASS = 'class'; - const TYPE_INTERFACE = 'interface'; - const TYPE_TRAIT = 'trait'; /** @var PhpNamespace|NULL */ @@ -99,7 +97,7 @@ public function __toString() foreach ($this->consts as $const) { $consts[] = Helpers::formatDocComment($const->getComment()) . ($const->getVisibility() ? $const->getVisibility() . ' ' : '') - . 'const ' . $const->getName() . ' = ' . Helpers::dump($const->getValue()) . ";\n"; + . 'const ' . $const->getName() . ' = ' . Helpers::dump($const->getValue()) . ';'; } $properties = []; @@ -107,7 +105,7 @@ public function __toString() $properties[] = Helpers::formatDocComment($property->getComment()) . ($property->getVisibility() ?: 'public') . ($property->isStatic() ? ' static' : '') . ' $' . $property->getName() . ($property->value === NULL ? '' : ' = ' . Helpers::dump($property->value)) - . ";\n"; + . ';'; } $mapper = function (array $arr) { @@ -124,8 +122,8 @@ public function __toString() . ($this->name ? "\n" : '') . "{\n" . Strings::indent( ($this->traits ? implode("\n", $traits) . "\n\n" : '') - . ($this->consts ? implode('', $consts) . "\n" : '') - . ($this->properties ? implode("\n", $properties) . "\n" : '') + . ($this->consts ? implode("\n", $consts) . "\n\n" : '') + . ($this->properties ? implode("\n\n", $properties) . "\n\n" : '') . ($this->methods ? "\n" . implode("\n\n\n", $this->methods) . "\n\n" : ''), 1) . '}' ) . ($this->name ? "\n" : '');