Skip to content

Commit 2a019f1

Browse files
committed
added Blueprint, replaces LatteRenderer, DataClassGenerator, {formPrint}, {formClassPrint}
1 parent bbb18f4 commit 2a019f1

File tree

10 files changed

+249
-290
lines changed

10 files changed

+249
-290
lines changed

src/Bridges/FormsLatte/FormMacros.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ public function macroFormPrint(MacroNode $node, PhpWriter $writer)
322322

323323
$node->tokenizer->reset();
324324
return $writer->write(
325-
'Nette\Bridges\FormsLatte\Runtime::render' . $node->name . '('
325+
'Nette\Forms\Blueprint::' . ($node->name === 'formPrint' ? 'latte' : 'dataClass') . '('
326326
. ($name[0] === '$'
327327
? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]'
328328
: '$this->global->uiControl[%node.word]')

src/Bridges/FormsLatte/Nodes/FormPrintNode.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ public static function create(Tag $tag): static
3939
public function print(PrintContext $context): string
4040
{
4141
return $context->format(
42-
'Nette\Bridges\FormsLatte\Runtime::render%raw('
42+
'Nette\Forms\Blueprint::%raw('
4343
. ($this->name
4444
? 'is_object($ʟ_tmp = %node) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]'
4545
: 'end($this->global->formsStack)')
4646
. ') %2.line; exit;',
47-
$this->mode,
47+
$this->mode === 'formPrint' ? 'latte' : 'dataClass',
4848
$this->name,
4949
$this->position,
5050
);

src/Bridges/FormsLatte/Runtime.php

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

1010
namespace Nette\Bridges\FormsLatte;
1111

12-
use Latte;
1312
use Nette;
1413
use Nette\Forms\Form;
1514
use Nette\Utils\Html;
@@ -76,42 +75,6 @@ public static function renderFormEnd(Form $form, bool $withTags = true): string
7675
}
7776

7877

79-
/**
80-
* Generates blueprint of form.
81-
*/
82-
public static function renderFormPrint(Form $form): void
83-
{
84-
$blueprint = class_exists(Latte\Runtime\Blueprint::class)
85-
? new Latte\Runtime\Blueprint
86-
: new Latte\Essential\Blueprint;
87-
$end = $blueprint->printCanvas();
88-
$blueprint->printHeader('Form ' . $form->getName());
89-
$blueprint->printCode((new Nette\Forms\Rendering\LatteRenderer)->render($form), 'latte');
90-
echo $end;
91-
}
92-
93-
94-
/**
95-
* Generates blueprint of form data class.
96-
*/
97-
public static function renderFormClassPrint(Form $form): void
98-
{
99-
$blueprint = class_exists(Latte\Runtime\Blueprint::class)
100-
? new Latte\Runtime\Blueprint
101-
: new Latte\Essential\Blueprint;
102-
$end = $blueprint->printCanvas();
103-
$blueprint->printHeader('Form Data Class ' . $form->getName());
104-
$generator = new Nette\Forms\Rendering\DataClassGenerator;
105-
$blueprint->printCode($generator->generateCode($form));
106-
if (PHP_VERSION_ID >= 80000) {
107-
$generator->propertyPromotion = true;
108-
$blueprint->printCode($generator->generateCode($form));
109-
}
110-
111-
echo $end;
112-
}
113-
114-
11578
public static function item($item, $global): object
11679
{
11780
if (is_object($item)) {

src/Forms/Blueprint.php

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
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\Forms;
11+
12+
13+
/**
14+
* Generates blueprints for forms.
15+
*/
16+
final class Blueprint
17+
{
18+
private const ClassNameSuffix = 'FormData';
19+
20+
21+
/**
22+
* Generates blueprint of form Latte template.
23+
*/
24+
public static function latte(Form $form, bool $exit = true): void
25+
{
26+
$bp = new self;
27+
$bp->printBegin();
28+
$bp->printHeader('Form ' . $form->getName());
29+
$bp->printCode($bp->generateLatte($form), 'latte');
30+
$bp->printEnd();
31+
if ($exit) {
32+
exit;
33+
}
34+
}
35+
36+
37+
/**
38+
* Generates blueprint of form data class.
39+
*/
40+
public static function dataClass(Form $form, bool $exit = true): void
41+
{
42+
$bp = new self;
43+
$bp->printBegin();
44+
$bp->printHeader('Form Data Class ' . $form->getName());
45+
$bp->printCode($bp->generateDataClass($form), 'php');
46+
if (PHP_VERSION_ID >= 80000) {
47+
$bp->printCode($bp->generateDataClass($form, true), 'php');
48+
}
49+
$bp->printEnd();
50+
if ($exit) {
51+
exit;
52+
}
53+
}
54+
55+
56+
private function printBegin(): void
57+
{
58+
echo '<script src="https://nette.github.io/resources/prism/prism.js"></script>';
59+
echo '<link rel="stylesheet" href="https://nette.github.io/resources/prism/prism.css">';
60+
echo "<div style='all:initial; position:fixed; overflow:auto; z-index:1000; left:0; right:0; top:0; bottom:0; color:black; background:white; padding:1em'>\n";
61+
}
62+
63+
64+
private function printEnd(): void
65+
{
66+
echo "</div>\n";
67+
}
68+
69+
70+
private function printHeader(string $string): void
71+
{
72+
echo "<h1 style='all:initial; display:block; font-size:2em; margin:1em 0'>",
73+
htmlspecialchars($string),
74+
"</h1>\n";
75+
}
76+
77+
78+
private function printCode(string $code, string $lang): void
79+
{
80+
echo '<pre><code class="language-', htmlspecialchars($lang), '">',
81+
htmlspecialchars($code),
82+
"</code></pre>\n";
83+
}
84+
85+
86+
public function generateLatte(Form $form): string
87+
{
88+
$dict = new \SplObjectStorage;
89+
$dummyForm = new class extends Form {
90+
protected function receiveHttpData(): ?array
91+
{
92+
return [];
93+
}
94+
};
95+
96+
foreach ($form->getControls() as $input) {
97+
$dict[$input] = $dummyInput = new class extends Controls\BaseControl {
98+
public $inner;
99+
100+
101+
public function getLabel($caption = null)
102+
{
103+
return $this->inner->getLabel()
104+
? '{label ' . $this->inner->lookupPath(Form::class) . '/}'
105+
: null;
106+
}
107+
108+
109+
public function getControl()
110+
{
111+
return '{input ' . $this->inner->lookupPath(Form::class) . '}';
112+
}
113+
114+
115+
public function isRequired(): bool
116+
{
117+
return $this->inner->isRequired();
118+
}
119+
120+
121+
public function getOption($key)
122+
{
123+
return $key === 'rendered'
124+
? parent::getOption($key)
125+
: $this->inner->getOption($key);
126+
}
127+
};
128+
$dummyInput->inner = $input;
129+
$dummyForm->addComponent($dummyInput, (string) $dict->count());
130+
$dummyInput->addError('{inputError ' . $input->lookupPath(Form::class) . '}');
131+
}
132+
133+
foreach ($form->getGroups() as $group) {
134+
$dummyGroup = $dummyForm->addGroup();
135+
foreach ($group->getOptions() as $k => $v) {
136+
$dummyGroup->setOption($k, $v);
137+
}
138+
139+
foreach ($group->getControls() as $control) {
140+
if ($dict[$control]) {
141+
$dummyGroup->add($dict[$control]);
142+
}
143+
}
144+
}
145+
146+
$renderer = clone $form->getRenderer();
147+
$dummyForm->setRenderer($renderer);
148+
$dummyForm->onRender = $form->onRender;
149+
$dummyForm->fireRenderEvents();
150+
151+
if ($renderer instanceof Rendering\DefaultFormRenderer) {
152+
$renderer->wrappers['error']['container'] = $renderer->getWrapper('error container')->setAttribute('n:ifcontent', true);
153+
$renderer->wrappers['error']['item'] = $renderer->getWrapper('error item')->setAttribute('n:foreach', '$form->getOwnErrors() as $error');
154+
$renderer->wrappers['control']['errorcontainer'] = $renderer->getWrapper('control errorcontainer')->setAttribute('n:ifcontent', true);
155+
$dummyForm->addError('{$error}');
156+
157+
ob_start();
158+
$dummyForm->render('end');
159+
$end = ob_get_clean();
160+
}
161+
162+
ob_start();
163+
$dummyForm->render();
164+
$body = ob_get_clean();
165+
166+
$body = str_replace($dummyForm->getElementPrototype()->startTag(), '<form n:name="' . $form->getName() . '">', $body);
167+
$body = str_replace($end ?? '', '</form>', $body);
168+
return $body;
169+
}
170+
171+
172+
public function generateDataClass(
173+
Container $container,
174+
?bool $propertyPromotion = false,
175+
?string $baseName = null
176+
): string
177+
{
178+
$baseName = $baseName ?? preg_replace('~Form$~', '', ucwords((string) $container->getName()));
179+
$nextCode = '';
180+
$props = [];
181+
foreach ($container->getComponents() as $name => $input) {
182+
if ($input instanceof Controls\BaseControl && $input->isOmitted()) {
183+
continue;
184+
} elseif ($input instanceof Controls\Checkbox) {
185+
$type = 'bool';
186+
} elseif ($input instanceof Controls\MultiChoiceControl) {
187+
$type = 'array';
188+
} elseif ($input instanceof Controls\ChoiceControl) {
189+
$type = 'string|int';
190+
if (!$input->isRequired()) {
191+
$type .= '|null';
192+
}
193+
} elseif ($input instanceof Controls\HiddenField || $input instanceof Controls\TextBase) {
194+
$type = 'string';
195+
foreach ($input->getRules() as $rule) {
196+
if ($rule->validator === Form::Integer) {
197+
$type = 'int';
198+
break;
199+
}
200+
}
201+
202+
if (!$input->isRequired()) {
203+
$type = '?' . $type;
204+
}
205+
} elseif ($input instanceof Controls\UploadControl) {
206+
$type = '\Nette\Http\FileUpload';
207+
if (!$input->isRequired()) {
208+
$type = '?' . $type;
209+
}
210+
} elseif ($input instanceof Container) {
211+
$type = $baseName . ucwords($name);
212+
$nextCode .= $this->generateDataClass($input, $propertyPromotion, $type);
213+
$type .= self::ClassNameSuffix;
214+
} else {
215+
$type = '';
216+
}
217+
218+
$props[] = 'public ' . ($type ? $type . ' ' : '') . '$' . $name;
219+
}
220+
221+
$class = $baseName . self::ClassNameSuffix;
222+
return "class $class\n"
223+
. "{\n"
224+
. ($propertyPromotion
225+
? "\tpublic function __construct(\n"
226+
. ($props ? "\t\t" . implode(",\n\t\t", $props) . ",\n" : '')
227+
. "\t) {\n\t}\n"
228+
: ($props ? "\t" . implode(";\n\t", $props) . ";\n" : '')
229+
)
230+
. "}\n\n"
231+
. $nextCode;
232+
}
233+
}

src/Forms/Rendering/DataClassGenerator.php

Lines changed: 4 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99

1010
namespace Nette\Forms\Rendering;
1111

12-
use Nette\Forms\Container;
13-
use Nette\Forms\Controls;
12+
use Nette\Forms\Blueprint;
1413
use Nette\Forms\Form;
1514

1615

1716
/**
1817
* Generates blueprint of form data class.
18+
* @deprecated use Nette\Latte\Blueprint::dataClass()
1919
*/
2020
final class DataClassGenerator
2121
{
@@ -29,68 +29,9 @@ final class DataClassGenerator
2929
public $useSmartObject = true;
3030

3131

32+
/** @deprecated use Nette\Latte\Blueprint::dataClass() */
3233
public function generateCode(Form $form, ?string $baseName = null): string
3334
{
34-
$baseName = $baseName ?? preg_replace('~Form$~', '', ucwords((string) $form->getName()));
35-
return $this->processContainer($form, $baseName);
36-
}
37-
38-
39-
private function processContainer(Container $container, string $baseName): string
40-
{
41-
$nextCode = '';
42-
$props = [];
43-
foreach ($container->getComponents() as $name => $input) {
44-
if ($input instanceof Controls\BaseControl && $input->isOmitted()) {
45-
continue;
46-
} elseif ($input instanceof Controls\Checkbox) {
47-
$type = 'bool';
48-
} elseif ($input instanceof Controls\MultiChoiceControl) {
49-
$type = 'array';
50-
} elseif ($input instanceof Controls\ChoiceControl) {
51-
$type = 'string|int';
52-
if (!$input->isRequired()) {
53-
$type .= '|null';
54-
}
55-
} elseif ($input instanceof Controls\HiddenField || $input instanceof Controls\TextBase) {
56-
$type = 'string';
57-
foreach ($input->getRules() as $rule) {
58-
if ($rule->validator === Form::Integer) {
59-
$type = 'int';
60-
break;
61-
}
62-
}
63-
64-
if (!$input->isRequired()) {
65-
$type = '?' . $type;
66-
}
67-
} elseif ($input instanceof Controls\UploadControl) {
68-
$type = '\Nette\Http\FileUpload';
69-
if (!$input->isRequired()) {
70-
$type = '?' . $type;
71-
}
72-
} elseif ($input instanceof Container) {
73-
$type = $baseName . ucwords($name);
74-
$nextCode .= $this->processContainer($input, $type);
75-
$type .= $this->classNameSuffix;
76-
} else {
77-
$type = '';
78-
}
79-
80-
$props[] = 'public ' . ($type ? $type . ' ' : '') . '$' . $name;
81-
}
82-
83-
$class = $baseName . $this->classNameSuffix;
84-
return "class $class\n"
85-
. "{\n"
86-
. ($this->useSmartObject ? "\tuse \\Nette\\SmartObject;\n\n" : '')
87-
. ($this->propertyPromotion
88-
? "\tpublic function __construct(\n"
89-
. ($props ? "\t\t" . implode(",\n\t\t", $props) . ",\n" : '')
90-
. "\t) {\n\t}\n"
91-
: ($props ? "\t" . implode(";\n\t", $props) . ";\n" : '')
92-
)
93-
. "}\n\n"
94-
. $nextCode;
35+
return (new Blueprint)->generateDataClass($form, $this->propertyPromotion, $baseName);
9536
}
9637
}

0 commit comments

Comments
 (0)