Skip to content

Commit

Permalink
latte 3
Browse files Browse the repository at this point in the history
  • Loading branch information
MartkCz authored and f3l1x committed Aug 5, 2022
1 parent 642c0fe commit 5bafb56
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 13 deletions.
17 changes: 17 additions & 0 deletions .docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ $multiplier->addCreateButton('Add 5', 5); // add five containers

### Macros

Latte 2

```latte
{form multiplier}
<div n:multiplier="multiplier">
Expand All @@ -54,3 +56,18 @@ $multiplier->addCreateButton('Add 5', 5); // add five containers
{btnCreate $form[multiplier]:5}
{/form}
```

Latte 3

```latte
{form multiplier}
<div n:multiplier="multiplier">
<input n:name="text">
{multiplier:remove class: myClass}
</div>
{multiplier:add multiplier class: myClass}
{multiplier:add multiplier:5}
{/form}
```

7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"codeception/codeception": "^4.0.0",
"codeception/module-asserts": "^1.3",
"codeception/module-phpbrowser": "^1.0",
"latte/latte": "^2.7.0",
"latte/latte": "^3.0.0",
"nette/application": "^3.0.0",
"nette/di": "^3.0.0",
"ninjify/qa": "^0.12",
Expand All @@ -38,7 +38,10 @@
"prefer-stable": true,
"minimum-stability": "dev",
"config": {
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"extra": {
"branch-alias": {
Expand Down
5 changes: 3 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ includes:
- vendor/phpstan/phpstan-nette/rules.neon

parameters:
ignoreErrors:
- '/Call to deprecated method fetchWords\(\) of class Latte\\MacroTokens./' # @todo https://github.com/contributte/forms-multiplier/issues/63
excludePaths:
analyse:
- src/Macros/MultiplierMacros.php
27 changes: 18 additions & 9 deletions src/DI/MultiplierExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

use Contributte\FormMultiplier\Macros\MultiplierMacros;
use Contributte\FormMultiplier\Multiplier;
use Nette;
use Latte\Engine;
use Nette\Bridges\ApplicationLatte\LatteFactory;
use Nette\DI\CompilerExtension;
use Nette\DI\Definitions\FactoryDefinition;
use Nette\DI\Definitions\Statement;
use Nette\DI\InvalidConfigurationException;
use Nette\PhpGenerator\ClassType;
use Nette\Schema\Expect;
use Nette\Schema\Schema;
use stdClass;
Expand All @@ -23,24 +28,28 @@ public function getConfigSchema(): Schema
public function beforeCompile(): void
{
$builder = $this->getContainerBuilder();
$factory = $builder->getDefinitionByType(LatteFactory::class);

$latteFactoryDefinition = $builder->getDefinition('latte.latteFactory');
if ($latteFactoryDefinition instanceof Nette\DI\Definitions\FactoryDefinition === false) {
throw new Nette\DI\InvalidConfigurationException(
if (!$factory instanceof FactoryDefinition) {
throw new InvalidConfigurationException(
sprintf(
'latte.latteFactory service definition must be of type %s, not %s',
Nette\DI\Definitions\FactoryDefinition::class,
get_class($latteFactoryDefinition)
FactoryDefinition::class,
get_class($factory)
)
);
}

$resultDefinition = $latteFactoryDefinition->getResultDefinition();
$resultDefinition = $factory->getResultDefinition();

$resultDefinition->addSetup(MultiplierMacros::class . '::install(?->getCompiler())', ['@self']);
if (version_compare(Engine::VERSION, '3', '<')) { // @phpstan-ignore-line
$resultDefinition->addSetup(MultiplierMacros::class . '::install(?->getCompiler())', ['@self']);
} else {
$resultDefinition->addSetup('addExtension', [new Statement(\Contributte\FormMultiplier\Latte\Extension\MultiplierExtension::class)]);
}
}

public function afterCompile(Nette\PhpGenerator\ClassType $class): void
public function afterCompile(ClassType $class): void
{
/** @var stdClass $config */
$config = $this->getConfig();
Expand Down
26 changes: 26 additions & 0 deletions src/Latte/Extension/MultiplierExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

namespace Contributte\FormMultiplier\Latte\Extension;

use Contributte\FormMultiplier\Latte\Extension\Node\MultiplierAddNode;
use Contributte\FormMultiplier\Latte\Extension\Node\MultiplierNode;
use Contributte\FormMultiplier\Latte\Extension\Node\MultiplierRemoveNode;
use Latte\Extension;

final class MultiplierExtension extends Extension
{

/**
* @return array<string, callable>
*/
public function getTags(): array
{
return [
'multiplier' => [MultiplierNode::class, 'create'],
'n:multiplier' => [MultiplierNode::class, 'create'],
'multiplier:remove' => [MultiplierRemoveNode::class, 'create'],
'multiplier:add' => [MultiplierAddNode::class, 'create'],
];
}

}
77 changes: 77 additions & 0 deletions src/Latte/Extension/Node/MultiplierAddNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php declare(strict_types = 1);

namespace Contributte\FormMultiplier\Latte\Extension\Node;

use Contributte\FormMultiplier\Multiplier;
use Contributte\FormMultiplier\Submitter;
use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
use Latte\Compiler\Nodes\Php\ExpressionNode;
use Latte\Compiler\Nodes\Php\Scalar\StringNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
use LogicException;
use Nette\ComponentModel\IComponent;
use Nette\Forms\Container;
use Nette\Forms\SubmitterControl;

final class MultiplierAddNode extends StatementNode
{

/** @var ExpressionNode */
private $name;

/** @var ArrayNode */
private $attributes;

/** @var ExpressionNode */
private $part;

public static function create(Tag $tag): self
{
$tag->expectArguments('multiplier name');

$node = new self();
$node->name = $tag->parser->parseUnquotedStringOrExpression(false);

if ($tag->parser->stream->tryConsume(':') && !$tag->parser->stream->is(',')) {
$node->part = $tag->parser->isEnd()
? new StringNode('1')
: $tag->parser->parseUnquotedStringOrExpression();
} else {
$node->part = new StringNode('1');
}

$node->attributes = $tag->parser->parseArguments();

return $node;
}

public function print(PrintContext $context): string
{
return $context->format(
($this->name instanceof StringNode
? '$ʟ_multiplier = end($this->global->formsStack)[%node];'
: '$ʟ_multiplier = is_object($ʟ_tmp = %node) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp];')
. 'if ($ʟ_input = %raw::getCreateButton($ʟ_multiplier, %node)) {'
. 'echo $ʟ_input->getControl()'
. ($this->attributes->items ? '->addAttributes(%node)' : '')
. ';'
. '} %4.line',
$this->name,
self::class,
$this->part,
$this->attributes,
$this->position
);
}

/**
* @param int|string $buttonId
*/
public static function getCreateButton(Multiplier $multiplier, $buttonId): ?Submitter
{
return $multiplier->getCreateButtons()[$buttonId] ?? null;
}

}
66 changes: 66 additions & 0 deletions src/Latte/Extension/Node/MultiplierNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php declare(strict_types = 1);

namespace Contributte\FormMultiplier\Latte\Extension\Node;

use Generator;
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\Php\ExpressionNode;
use Latte\Compiler\Nodes\Php\Scalar\StringNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\Position;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;

final class MultiplierNode extends StatementNode
{

/** @var ExpressionNode */
private $name;

/** @var AreaNode */
private $content;

/**
* @return Generator<int, ?mixed[], array{AreaNode, ?Tag}, self>
*/
public static function create(Tag $tag): Generator
{
$tag->outputMode = $tag::OutputRemoveIndentation;
$tag->expectArguments();

$node = new static;
$node->name = $tag->parser->parseUnquotedStringOrExpression();

[$node->content] = yield;

return $node;
}

public function print(PrintContext $context): string
{
return $context->format(
'$multiplier = '
. ($this->name instanceof StringNode
? 'end($this->global->formsStack)[%node];'
: 'is_object($ʟ_tmp = %node) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp];')
. 'foreach ($multiplier->getContainers() as $formContainer) {'
. "\n"
. '$this->global->formsStack[] = $formContainer;'
. ' %line %node ' // content
. 'array_pop($this->global->formsStack);'
. "\n"
. '}'
. '$formContainer = end($this->global->formsStack);'
. "\n\n",
$this->name,
$this->position,
$this->content
);
}
public function &getIterator(): \Generator
{
yield $this->name;
yield $this->content;
}

}
57 changes: 57 additions & 0 deletions src/Latte/Extension/Node/MultiplierRemoveNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php declare(strict_types = 1);

namespace Contributte\FormMultiplier\Latte\Extension\Node;

use Contributte\FormMultiplier\Multiplier;
use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
use LogicException;
use Nette\ComponentModel\IComponent;
use Nette\Forms\Container;
use Nette\Forms\SubmitterControl;

final class MultiplierRemoveNode extends StatementNode
{

/** @var ArrayNode */
private $attributes;

public static function create(Tag $tag): self
{
$node = new self();
$node->attributes = $tag->parser->parseArguments();

return $node;
}

public function print(PrintContext $context): string
{
return $context->format(
'if ($ʟ_input = %raw::getRemoveButton($this->global->formsStack)) {'
. 'echo $ʟ_input->getControl()'
. ($this->attributes->items ? '->addAttributes(%1.node)' : '')
. ';'
. '} %2.line',
self::class,
$this->attributes,
$this->position
);
}

/**
* @param Container[] $formsStack
*/
public static function getRemoveButton(array $formsStack): ?IComponent
{
$container = end($formsStack);

if (!$container || !$container->getParent() instanceof Multiplier) {
throw new LogicException('{multiplier:remove} macro must be inside {multiplier} macro.');
}

return $container->getComponent(Multiplier::SUBMIT_REMOVE_NAME, false);
}

}

0 comments on commit 5bafb56

Please sign in to comment.