Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ $processor->generate(new MyOtherForm());
| [`CallbackGenerator`](src/Form/CallbackGenerator.php) | `CallbackGenerator('generate')` | `$builder->generates([$this, 'generate'])` | Define the method to use for generate the form value. The method must be declared as public on the form class. |
| [`Csrf`](src/Form/Csrf.php) | `Csrf(tokenId: 'MyToken')` | `$builder->csrf()->tokenId('MyToken')` | Add a CSRF element on the form. |

### On method

| Attribute | Example | Translated to | Purpose |
|------------------------------------------------------------|--------------------------------------|-------------------------------------------------------|-------------------------------------------------------------|
| [`AsConstraint`](src/Constraint/AsConstraint.php) | `AsConstraint('validateFoo')` | `$builder->satisfy([$this, 'validateFoo'])` | Use the method as constraint for the target element. |
| [`AsArrayConstraint`](src/Aggregate/AsArrayConstraint.php) | `AsArrayConstraint('validateFoo')` | `$builder->arrayConstraint([$this, 'validateFoo'])` | Use the method as constraint for the target array element. |
| [`AsFilter`](src/Child/AsFilter.php) | `AsFilter('filterFoo')` | `$builder->filter([$this, 'filterFoo'])` | Use the method as filter for the target element. |
| [`AsTransformer`](src/Element/AsTransformer.php) | `AsTransformer('transformFoo')` | `$builder->transformer([$this, 'transformFoo'])` | Use the method as HTTP transformer for the target element. |
| [`AsModelTransformer`](src/Child/AsModelTransformer.php) | `AsModelTransformer('transformFoo')` | `$builder->modelTransformer([$this, 'transformFoo'])` | Use the method as model transformer for the target element. |

### On button property

| Attribute | Example | Translated to | Purpose |
Expand All @@ -153,6 +163,8 @@ $processor->generate(new MyOtherForm());
| [`DefaultValue`](src/Child/DefaultValue.php) | `DefaultValue(42)` | `...->configureField($elementBuilder)` | Define the default value of the input. |
| [`Dependencies`](src/Child/Dependencies.php) | `Dependencies('foo', 'bar')` | `...->depends('foo', 'bar')` | Declare dependencies on the current input. Dependencies will be submitted before the current field. |
| [`GetSet`](src/Child/GetSet.php) | `GetSet('realField')` | `...->getter('realField')->setter('realField')` | Enable hydration and extraction of the entity. |
| [`CallbackFilter`](src/Child/CallbackFilter.php) | `CallbackFilter('filterMethod')` | `...->filter([$this, 'filterMethod'])` | Add a filter on the current child using a method. |
| [`HttpField`](src/Child/HttpField.php) | `HttpField('_field')` | `...->httpField(new ArrayOffsetHttpField('_field'))` | Define the http field name to use on the current child, instead of use the property name. |
| **Element** | | | |
| [`CallbackConstraint`](src/Constraint/CallbackConstraint.php) | `CallbackConstraint('validateInput')` | `...->satisfy([$this, 'validateInput'])` | Validate an input using a method. |
| [`Satisfy`](src/Constraint/Satisfy.php) | `Satisfy(MyConstraint::class, ['opt' => 'val'])` | `...->satisfy(new MyConstraint(['opt' => 'val']))` | Add a constraint on the input. Prefer directly use the constraint class as attribute if possible. |
Expand All @@ -162,13 +174,17 @@ $processor->generate(new MyOtherForm());
| [`Raw`](src/Element/Raw.php) | `Raw` | `...->raw()` | For number elements. Use native PHP cast instead of locale parsing for convert number. |
| [`TransformerError`](src/Element/TransformerError.php) | `TransformerError(message: 'Invalid value provided')` | `...->transformerErrorMessage('Invalid value provided')` | Configure error handling of transformer exceptions. |
| [`IgnoreTransformerException`](src/Element/IgnoreTransformerException.php) | `IgnoreTransformerException` | `...->ignoreTransformerException()` | Ignore transformer exception. If enable and an exception occurs, the raw value will be used. |
| [`Required`](src/Element/Required.php) | `Required` | `...->required()` | Mark the element as required. The error message can be defined as parameter of the attribute. |
| **DateTimeElement** | | | |
| [`DateFormat`](src/Element/Date/DateFormat.php) | `DateFormat('d/m/Y H:i')` | `...->format('d/m/Y H:i')` | Define the input date format. |
| [`DateTimeClass`](src/Element/Date/DateTimeClass.php) | `DateTimeClass(Carbon::class)` | `...->className(Carbon::class)` | Define date time class to use on for parse the date. |
| [`ImmutableDateTime`](src/Element/Date/ImmutableDateTime.php) | `ImmutableDateTime` | `...->immutable()` | Use `DateTimeImmutable` as date time class. |
| [`Timezone`](src/Element/Date/Timezone.php) | `Timezone('Europe/Paris')` | `...->timezone('Europe/Paris')` | Define the parsing and normalized timezone to use. |
| [`AfterField`](src/Element/Date/AfterField.php) | `AfterField('otherField')` | `...->afterField('otherField')` | Add a greater than an other field constraint to the current element. |
| [`BeforeField`](src/Element/Date/BeforeField.php) | `BeforeField('otherField')` | `...->beforeField('otherField')` | Add a less than an other field constraint to the current element. |
| **ArrayElement** | | | |
| [`ArrayConstraint`](src/Aggregate/ArrayConstraint.php) | `ArrayConstraint(MyConstraint::class, ['opt' => 'val'])` | `...->arrayConstraint(new MyConstraint(['opt' => 'val']))` | Add a constraint on the whole array element. |
| [`CallbackArrayConstraint`](src/Aggregate/CallbackArrayConstraint.php) | `CallbackArrayConstraint('validateInput')` | `...->arrayConstraint([$this, 'validateInput'])` | Add a constraint on the whole array element, using a form method. |
| [`Count`](src/Aggregate/Count.php) | `Count(min: 3, max: 6)` | `...->arrayConstraint(new Count(min: 3, max: 6))` | Add a Count constraint on the array element. |
| [`ElementType`](src/Aggregate/ElementType.php) | `ElementType(IntegerElement::class, 'configureElement')` | `...->element(IntegerElement::class, [$this, 'configureElement'])` | Define the array element type. A configuration callback method can be define for configure the inner element. |
| [`ArrayTransformer`](src/Aggregate/ArrayTransformer.php) | `ArrayTransformer(MyTransformer::class, ['ctroarg'])` | `...->arrayTransformer(new MyTransformer('ctorarg))` | Add a transformer for the whole array input. |
4 changes: 4 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<testsuites>
<testsuite name="All Test Suite">
<directory suffix="Test.php">./tests</directory>
<exclude>./tests/Php81</exclude>
</testsuite>
<testsuite name="PHP compatibility">
<directory suffix="Test.php" phpVersion="8.1">./tests/Php81</directory>
</testsuite>
</testsuites>
</phpunit>
36 changes: 29 additions & 7 deletions src/Aggregate/ArrayConstraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@
use Bdf\Form\Attribute\ChildBuilderAttributeInterface;
use Bdf\Form\Attribute\Constraint\Satisfy;
use Bdf\Form\Attribute\Processor\CodeGenerator\AttributesProcessorGenerator;
use Bdf\Form\Attribute\Processor\GenerateConfiguratorStrategy;
use Bdf\Form\Attribute\Processor\CodeGenerator\ObjectInstantiation;
use Bdf\Form\Child\ChildBuilderInterface;
use InvalidArgumentException;
use Nette\PhpGenerator\Literal;
use Symfony\Component\Validator\Constraint;

use function is_object;
use function is_string;

/**
* Add a constraint on the whole array element
* Use Satisfy, or directly the constraint as attribute for add a constraint on one array item
Expand All @@ -28,6 +32,10 @@
* {
* #[ArrayConstraint(Unique::class, ['message' => 'My error'])]
* private ArrayElement $values;
*
* // or on PHP 8.1
* #[ArrayConstraint(new Unique(['message' => 'My error']))]
* private ArrayElement $values;
* }
* </code>
*
Expand All @@ -43,12 +51,19 @@ final class ArrayConstraint implements ChildBuilderAttributeInterface
{
public function __construct(
/**
* The constraint class name
* The constraint
*
* @var class-string<Constraint>
* You can use a class name, and provider arguments on the next parameter,
* or directly use the constraint instance.
*
* When a constraint instance is used, in case of code generation,
* the constructor parameters will be deduced from public properties of the constraint.
* This may not work if the constraint has a complex constructor.
*
* @var class-string<Constraint>|Constraint
* @readonly
*/
private string $constraint,
private string|Constraint $constraint,
/**
* Constraint's constructor options
*
Expand All @@ -57,6 +72,9 @@ public function __construct(
*/
private mixed $options = null
) {
if (is_object($constraint) && $options !== null) {
throw new InvalidArgumentException('Cannot use options with constraint instance');
}
}

/**
Expand All @@ -72,8 +90,12 @@ public function applyOnChildBuilder(AttributeForm $form, ChildBuilderInterface $
*/
public function generateCodeForChildBuilder(string $name, AttributesProcessorGenerator $generator, AttributeForm $form): void
{
$constraint = $generator->useAndSimplifyType($this->constraint);

$generator->line('$?->arrayConstraint(?::class, ?);', [$name, new Literal($constraint), $this->options]);
if (is_string($this->constraint)) {
$constraint = $generator->useAndSimplifyType($this->constraint);
$generator->line('$?->arrayConstraint(?::class, ?);', [$name, new Literal($constraint), $this->options]);
} else {
$constraint = ObjectInstantiation::singleArrayParameter($this->constraint)->render($generator);
$generator->line('$?->arrayConstraint(?);', [$name, $constraint]);
}
}
}
45 changes: 45 additions & 0 deletions src/Aggregate/ArrayTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Bdf\Form\Attribute\Aggregate;

use Attribute;
use Bdf\Form\Attribute\Element\Transformer;
use Bdf\Form\Transformer\TransformerInterface;

/**
* Add a transformer on the array element, using a transformer class
*
* This attribute will simply set the array flag to true on the {@see Transformer} attribute.
*
* This attribute is equivalent to call :
* <code>
* $builder->string('foo')->arrayTransformer(new MyTransformer(...$arguments));
* </code>
*
* Usage:
* <code>
* class MyForm extends AttributeForm
* {
* #[ArrayTransformer(MyTransformer::class, ['foo', 'bar']), ElementType(IntegerElement::class)]
* private ArrayElement $foo;
* }
* </code>
*
* @see ArrayElementBuilder::arrayTransformer() The called method
* @see CallbackTransformer For use custom methods as transformer instead of class
* @see Transformer To add a transformer the item of the array
*
* @api
*/
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
class ArrayTransformer extends Transformer
{
/**
* @param class-string<TransformerInterface> $transformerClass The transformer class name
* @param array $constructorArguments Arguments to provide on the transformer constructor
*/
public function __construct(string $transformerClass, array $constructorArguments = [])
{
parent::__construct($transformerClass, $constructorArguments, true);
}
}
Loading