Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5126fb8

Browse files
shanginndg
authored andcommitted
added support for properties hooks [Closes #171]
1 parent bad08ce commit 5126fb8

File tree

10 files changed

+372
-12
lines changed

10 files changed

+372
-12
lines changed

‎composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nette/php-generator",
3-
"description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.3 features.",
3+
"description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.4 features.",
44
"keywords": ["nette", "php", "code", "scaffolding"],
55
"homepage": "https://nette.org",
66
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],

‎readme.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Are you looking for a tool to generate PHP code for [classes](#classes), [functi
88

99
<h3>
1010

11-
✅ Supports all the latest PHP features like [enums](#enums), [attributes](#attributes), etc.<br>
11+
✅ Supports all the latest PHP features like [property hooks](#property-hooks), [enums](#enums), [attributes](#attributes), etc.<br>
1212
✅ Allows you to easily modify [existing classes](#generating-from-existing-ones)<br>
1313
✅ Output compliant with [PSR-12 / PER coding style](#printer-and-psr-compliance)<br>
1414
✅ Highly mature, stable, and widely used library
@@ -665,6 +665,42 @@ class Demo
665665

666666
<!---->
667667

668+
Property Hooks
669+
--------------
670+
671+
You can also define property hooks (represented by the class [PropertyHook](https://api.nette.org/php-generator/master/Nette/PhpGenerator/PropertyHook.html)) for get and set operations, a feature introduced in PHP 8.4:
672+
673+
```php
674+
$class = new Nette\PhpGenerator\ClassType('Demo');
675+
$prop = $class->addProperty('firstName')
676+
->setType('string');
677+
678+
$prop->addHook('set', 'strtolower($value)')
679+
->addParameter('value')
680+
->setType('string');
681+
682+
$prop->addHook('get')
683+
->setBody('return ucfirst($this->firstName);');
684+
685+
echo $class;
686+
```
687+
688+
This generates:
689+
690+
```php
691+
class Demo
692+
{
693+
public string $firstName {
694+
set(string $value) => strtolower($value);
695+
get {
696+
return ucfirst($this->firstName);
697+
}
698+
}
699+
}
700+
```
701+
702+
<!---->
703+
668704
Namespace
669705
---------
670706

‎src/PhpGenerator/Printer.php

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public function printMethod(Method $method, ?PhpNamespace $namespace = null, boo
129129
}
130130

131131

132-
private function printFunctionBody(Closure|GlobalFunction|Method $function): string
132+
private function printFunctionBody(Closure|GlobalFunction|Method|PropertyHook $function): string
133133
{
134134
$code = Helpers::simplifyTaggedNames($function->getBody(), $this->namespace);
135135
$code = Strings::normalize($code);
@@ -313,7 +313,7 @@ protected function printUses(PhpNamespace $namespace, string $of = PhpNamespace:
313313
}
314314

315315

316-
protected function printParameters(Closure|GlobalFunction|Method $function, int $column = 0): string
316+
protected function printParameters(Closure|GlobalFunction|Method|PropertyHook $function, int $column = 0): string
317317
{
318318
$special = false;
319319
foreach ($function->getParameters() as $param) {
@@ -332,13 +332,13 @@ protected function printParameters(Closure|GlobalFunction|Method $function, int
332332
}
333333

334334

335-
private function formatParameters(Closure|GlobalFunction|Method $function, bool $multiline): string
335+
private function formatParameters(Closure|GlobalFunction|Method|PropertyHook $function, bool $multiline): string
336336
{
337337
$params = $function->getParameters();
338338
$res = '';
339339

340340
foreach ($params as $param) {
341-
$variadic = $function->isVariadic() && $param === end($params);
341+
$variadic = !$functioninstanceof PropertyHook && $function->isVariadic() && $param === end($params);
342342
$attrs = $this->printAttributes($param->getAttributes(), inline: true);
343343
$res .=
344344
$this->printDocComment($param)
@@ -351,6 +351,7 @@ private function formatParameters(Closure|GlobalFunction|Method $function, bool
351351
. ($variadic ? '...' : '')
352352
. '$' . $param->getName()
353353
. ($param->hasDefaultValue() && !$variadic ? ' = ' . $this->dump($param->getDefaultValue()) : '')
354+
. ($param instanceof PromotedParameter ? $this->printHooks($param) : '')
354355
. ($multiline ? ",\n" : ', ');
355356
}
356357

@@ -386,13 +387,16 @@ private function printProperty(Property $property, bool $readOnlyClass = false):
386387
. ltrim($this->printType($type, $property->isNullable()) . '')
387388
. '$' . $property->getName());
388389

390+
$defaultValue = $property->getValue() === null && !$property->isInitialized()
391+
? ''
392+
: ' = ' . $this->dump($property->getValue(), strlen($def) + 3); // 3 = ' = '
393+
389394
return $this->printDocComment($property)
390395
. $this->printAttributes($property->getAttributes())
391396
. $def
392-
. ($property->getValue() === null && !$property->isInitialized()
393-
? ''
394-
: ' = ' . $this->dump($property->getValue(), strlen($def) + 3)) // 3 = ' = '
395-
. ";\n";
397+
. $defaultValue
398+
. ($this->printHooks($property) ?: ';')
399+
. "\n";
396400
}
397401

398402

@@ -452,6 +456,30 @@ protected function printAttributes(array $attrs, bool $inline = false): string
452456
}
453457

454458

459+
private function printHooks(Property|PromotedParameter $property): string
460+
{
461+
$hooks = $property->getHooks();
462+
if (!$hooks) {
463+
return '';
464+
}
465+
466+
foreach ($property->getHooks() as $type => $hook) {
467+
$hooks[$type] = $this->printDocComment($hook)
468+
. $this->printAttributes($hook->getAttributes())
469+
. ($hook->isFinal() ? 'final ' : '')
470+
. ($hook->getReturnReference() ? '&' : '')
471+
. $type
472+
. ($hook->getParameters() ? $this->printParameters($hook) : '')
473+
. ''
474+
. ($hook->isShort()
475+
? '=> ' . $hook->getBody() . ';'
476+
: "{\n" . $this->indent($this->printFunctionBody($hook)) . '}');
477+
}
478+
479+
return " {\n" . $this->indent(implode("\n", $hooks)) . "\n}";
480+
}
481+
482+
455483
public function setTypeResolving(bool $state = true): static
456484
{
457485
$this->resolveTypes = $state;

‎src/PhpGenerator/PromotedParameter.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@ public function validate(): void
2626
throw new Nette\InvalidStateException("Property \${$this->getName()}: Read-only properties are only supported on typed property.");
2727
}
2828
}
29+
30+
31+
public function __clone(): void
32+
{
33+
$this->hooks = array_map(fn($item) => $item ? clone $item : $item, $this->hooks);
34+
}
2935
}

‎src/PhpGenerator/Property.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,10 @@ public function validate(): void
106106
throw new Nette\InvalidStateException("Property \$$this->name: Read-only properties are only supported on typed property.");
107107
}
108108
}
109+
110+
111+
public function __clone(): void
112+
{
113+
$this->hooks = array_map(fn($item) => $item ? clone $item : $item, $this->hooks);
114+
}
109115
}

‎src/PhpGenerator/PropertyHook.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Nette\PhpGenerator;
6+
7+
use JetBrains\PhpStorm\Language;
8+
9+
10+
/**
11+
* Definition of a property hook.
12+
*/
13+
final class PropertyHook
14+
{
15+
use Traits\AttributeAware;
16+
use Traits\CommentAware;
17+
18+
private string $body = '';
19+
private bool $short = false;
20+
private bool $final = false;
21+
22+
/** @var Parameter[] */
23+
private array $parameters = [];
24+
private bool $returnReference = false;
25+
26+
27+
/** @param ?mixed[] $args */
28+
public function setBody(
29+
#[Language('PHP')]
30+
string $code,
31+
?array $args = null,
32+
bool $short = false,
33+
): static
34+
{
35+
$this->body = $args === null
36+
? $code
37+
: (new Dumper)->format($code, ...$args);
38+
$this->short = $short;
39+
return $this;
40+
}
41+
42+
43+
public function getBody(): string
44+
{
45+
return $this->body;
46+
}
47+
48+
49+
public function isShort(): bool
50+
{
51+
return $this->short && trim($this->body) !== '';
52+
}
53+
54+
55+
public function setFinal(bool $state = true): static
56+
{
57+
$this->final = $state;
58+
return $this;
59+
}
60+
61+
62+
public function isFinal(): bool
63+
{
64+
return $this->final;
65+
}
66+
67+
68+
/** @internal */
69+
public function setParameters(array $val): static
70+
{
71+
(function (Parameter ...$val) {})(...$val);
72+
$this->parameters = [];
73+
foreach ($val as $v) {
74+
$this->parameters[$v->getName()] = $v;
75+
}
76+
77+
return $this;
78+
}
79+
80+
81+
/** @internal */
82+
public function getParameters(): array
83+
{
84+
return $this->parameters;
85+
}
86+
87+
88+
/**
89+
* Adds a parameter. If it already exists, it overwrites it.
90+
* @param string $name without $
91+
*/
92+
public function addParameter(string $name): Parameter
93+
{
94+
return $this->parameters[$name] = new Parameter($name);
95+
}
96+
97+
98+
public function setReturnReference(bool $state = true): static
99+
{
100+
$this->returnReference = $state;
101+
return $this;
102+
}
103+
104+
105+
public function getReturnReference(): bool
106+
{
107+
return $this->returnReference;
108+
}
109+
}

‎src/PhpGenerator/PropertyHookType.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\PhpGenerator;
11+
12+
use Nette;
13+
14+
15+
/**
16+
* Property hook type.
17+
*/
18+
/*enum*/ final class PropertyHookType
19+
{
20+
use Nette\StaticClass;
21+
22+
public const Set = 'set';
23+
public const Get = 'get';
24+
25+
26+
/** @internal */
27+
public static function from(string $value): string
28+
{
29+
return $value === self::Set || $value === self::Get
30+
? $value
31+
: throw new \ValueError("'$value' is not a valid value of hook type");
32+
}
33+
}

‎src/PhpGenerator/Traits/PropertyLike.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
namespace Nette\PhpGenerator\Traits;
1111

12+
use Nette\PhpGenerator\PropertyHook;
13+
use Nette\PhpGenerator\PropertyHookType;
1214

1315

1416
/**
@@ -20,6 +22,9 @@ trait PropertyLike
2022

2123
private bool $readOnly = false;
2224

25+
/** @var array<string, ?PropertyHook> */
26+
private array $hooks = [PropertyHookType::Set => null, PropertyHookType::Get => null];
27+
2328

2429
public function setReadOnly(bool $state = true): static
2530
{
@@ -32,4 +37,45 @@ public function isReadOnly(): bool
3237
{
3338
return $this->readOnly;
3439
}
40+
41+
42+
/**
43+
* Replaces all hooks.
44+
* @param PropertyHook[] $hooks
45+
*/
46+
public function setHooks(array $hooks): static
47+
{
48+
(function (PropertyHook ...$hooks) {})(...$hooks);
49+
$this->hooks = $hooks;
50+
return $this;
51+
}
52+
53+
54+
/** @return array<string, PropertyHook> */
55+
public function getHooks(): array
56+
{
57+
return array_filter($this->hooks);
58+
}
59+
60+
61+
/** @param 'set'|'get' $type */
62+
public function addHook(string $type, string $shortBody = ''): PropertyHook
63+
{
64+
return $this->hooks[PropertyHookType::from($type)] = (new PropertyHook)
65+
->setBody($shortBody, short: true);
66+
}
67+
68+
69+
/** @param 'set'|'get' $type */
70+
public function getHook(string $type): ?PropertyHook
71+
{
72+
return $this->hooks[PropertyHookType::from($type)] ?? null;
73+
}
74+
75+
76+
/** @param 'set'|'get' $type */
77+
public function hasHook(string $type): bool
78+
{
79+
return isset($this->hooks[PropertyHookType::from($type)]);
80+
}
3581
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /