Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
php-versions: ['8,2', '8.3', '8.4']
php-versions: ['8.2', '8.3', '8.4']

runs-on: ubuntu-latest

Expand All @@ -37,7 +37,7 @@ jobs:

# https://github.com/marketplace/actions/check-php-syntax-errors
- name: Check PHP syntax errors
uses: overtrue/phplint@9
uses: overtrue/phplint@9.7.2

- name: Coding standards
run: ./vendor/bin/phpcs
Expand Down
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ To notify a user of an error with their form submission:
Symfony Form will automatically display an error message next to the input field. Error messages should have a unique ID and be associated with the form input via the `aria-describedby` attribute.
This is provided in the accessible form theme.


## Docs

- [Using accessible forms with Laravel](laravel.md)
- [Using accessible forms with Symfony](symfony.md)
- [Form options](form-options.md)
- Form helpers to create a form
- Accessible form theme
- GOV.UK Design System form theme
Expand Down
26 changes: 26 additions & 0 deletions docs/form-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Form options

## do_not_render

If you want to add a form field for validating request data, but you don't want to display this in your HTML form, you can use the 'do_not_render' option.
This accepts an array of element names to not render in the form HTML. This can be useful for things like pagination, that don't appear in the main form HTML but appear as links separately on the page.

Using this example, when the form is rendered to the view template, the page form element is skipped:

```php
// Form class
class MySearchForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('keywords', TextType::class)
->add('page', IntegerType::class, ['required' => false])
;
}
}
// Controller
$form = $this->createForm(MySearchForm::class, null, ['do_not_render' => ['page']]);
```

Please note, an alternative way to achieve this is to use the [allow_extra_fields](https://symfony.com/doc/current/reference/forms/types/form.html#allow-extra-fields) option, which allows additional fields to be passed into a form, but you need to take care of validation yourself.
30 changes: 15 additions & 15 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/8.0/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true">
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<php>
<ini name="error_reporting" value="-1"/>
<ini name="display_errors" value="1"/>
</php>
<testsuites>
<testsuite name="unit">
<directory>tests</directory>
</testsuite>
</testsuites>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.5/phpunit.xsd" backupGlobals="false" colors="true">
<php>
<ini name="error_reporting" value="-1"/>
<ini name="display_errors" value="1"/>
</php>
<testsuites>
<testsuite name="unit">
<directory>tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">src</directory>
</include>
</source>
</phpunit>
2 changes: 2 additions & 0 deletions src/FieldTypes/Html.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Studio24\AccessibleForms\FieldTypes;

use Symfony\Component\Form\AbstractType;
Expand Down
23 changes: 23 additions & 0 deletions src/Form.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<?php

declare(strict_types=1);

namespace Studio24\AccessibleForms;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

class Form extends AbstractType
Expand All @@ -16,8 +20,27 @@ public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);

// Disable HTML5 validation
$resolver->setDefaults([
'attr' => ['novalidate' => 'novalidate'],
'do_not_render' => [],
]);

$resolver->setAllowedTypes('do_not_render', 'array');
}

/**
* @return void
*/
public function finishView(FormView $view, FormInterface $form, array $options)
{
// Remove elements we do not want to render in HTML form
if (!empty($options['do_not_render'])) {
foreach ($options['do_not_render'] as $element) {
unset($view->children[$element]);
}
}

parent::finishView($view, $form, $options);
}
}
3 changes: 1 addition & 2 deletions src/Twig/AccessibleFormsExtension.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Studio24\AccessibleForms\Twig;
Expand Down Expand Up @@ -58,7 +59,6 @@ public function allErrors(FormView $form): array
$errors = [];
foreach ($form->children as $child) {
if (isset($child->vars['errors']) && count($child->vars['errors']) > 0) {

$id = $child->vars['id'];

if (!empty($child->vars['choices']) && !empty($child->vars['expanded']) && $child->vars['expanded'] === true) {
Expand Down Expand Up @@ -114,5 +114,4 @@ public function prefixOnErrors(string $string, FormView $form, string $prefix =
}
return $string;
}

}
55 changes: 55 additions & 0 deletions tests/DoNotRenderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Studio24\AccessibleForms\Tests;

use Studio24\AccessibleForms\Form;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Test\TypeTestCase;

class DoNotRenderTestForm extends Form
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('keywords', TextType::class)
->add('filters', ChoiceType::class, [
'choices' => ['Yellow' => 'Yellow', 'Orange' => 'Orange', 'White' => 'White'],
'expanded' => true,
'multiple' => true,
])
->add('page', IntegerType::class, ['required' => false])
;
}
}

/**
* Checks that fields listed in the `do_not_render` option are excluded from the
* actual rendered HTML output, not just removed from the FormView tree.
*
* @see https://docs.phpunit.de/en/12.4/writing-tests-for-phpunit.html
*/
class DoNotRenderTest extends TypeTestCase
{
use TwigTrait;

public function testDoNotRenderExcludesFieldFromHtml()
{
$options = [
'do_not_render' => ['page']
];
$form = $this->factory->create(DoNotRenderTestForm::class, null, $options);
$view = $form->createView();
$html = $this->renderForm($view);

/**
* Form element HTML is expected to be:
* <input type="number" id="do_not_render_test_form_page" name="do_not_render_test_form[page]" class="tbxforms-input" />
*/
$this->assertStringNotContainsString('<input type="number" id="do_not_render_test_form_page"', $html);
}
}
12 changes: 0 additions & 12 deletions tests/ExampleTest.php

This file was deleted.

49 changes: 49 additions & 0 deletions tests/TwigTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Studio24\AccessibleForms\Tests;

use Studio24\AccessibleForms\Twig\AccessibleFormsExtension;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormView;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Loader\ChainLoader;
use Twig\Loader\FilesystemLoader;
use Twig\RuntimeLoader\FactoryRuntimeLoader;

/**
* Class to help test Twig template functionality
*/
trait TwigTrait
{
/**
* Render a form's FormView through the library's accessible-forms Twig theme
*/
public function renderForm(FormView $view): string
{
$loader = new ChainLoader([
new ArrayLoader(['index.html.twig' => '{{ form(view) }}']),
new FilesystemLoader([
__DIR__ . '/../vendor/symfony/twig-bridge/Resources/views/Form',
__DIR__ . '/../src/Resources/views/Form',
]),
]);

$twig = new Environment($loader);
$twig->addExtension(new AccessibleFormsExtension());
$twig->addExtension(new FormExtension());
$twig->addExtension(new TranslationExtension());

$renderer = new FormRenderer(new TwigRendererEngine(['accessible-forms.html.twig'], $twig));
$twig->addRuntimeLoader(new FactoryRuntimeLoader([
FormRenderer::class => fn () => $renderer,
]));

return $twig->render('index.html.twig', ['view' => $view]);
}
}
Loading