Skip to content

Commit

Permalink
Validate slug/action/alias name
Browse files Browse the repository at this point in the history
Validation rules added using the addRule(Form::Pattern, ...) call, not using any custom validation callback because I want the JS validation to be also used and don't want to add a custom one.
  • Loading branch information
spaze committed Jan 14, 2025
1 parent 612650a commit 55f3916
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 5 deletions.
1 change: 1 addition & 0 deletions app/config/services.neon
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ services:
- MichalSpacekCz\Form\Controls\TrainingControlsFactory
- MichalSpacekCz\Form\DeletePersonalDataFormFactory
- MichalSpacekCz\Form\FormFactory
- MichalSpacekCz\Form\FormValidators
- MichalSpacekCz\Form\InterviewFormFactory(videoThumbnails: @interviewVideoThumbnails)
- MichalSpacekCz\Form\PostFormFactory
- MichalSpacekCz\Form\Pulse\PasswordsStorageAlgorithmFormFactory
Expand Down
24 changes: 24 additions & 0 deletions app/src/Form/FormValidators.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types = 1);

namespace MichalSpacekCz\Form;

use Contributte\Translation\Translator;
use Nette\Forms\Controls\TextInput;
use Nette\Forms\Form;

readonly class FormValidators
{

public function __construct(
private Translator $translator,
) {
}


public function addValidateSlugRules(TextInput $input): void
{
$input->addRule(Form::Pattern, $this->translator->translate('messages.forms.validateSlugParamsError'), '[a-z0-9.,_-]+');
}

}
4 changes: 3 additions & 1 deletion app/src/Form/PostFormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

public function __construct(
private FormFactory $factory,
private FormValidators $validators,
private Translator $translator,
private BlogPosts $blogPosts,
private BlogPostFactory $blogPostFactory,
Expand All @@ -62,8 +63,9 @@ public function create(callable $onSuccessAdd, callable $onSuccessEdit, DefaultT
$form->addText('title', 'Titulek:')
->setRequired('Zadejte prosím titulek')
->addRule(Form::MinLength, 'Titulek musí mít alespoň %d znaky', 3);
$form->addText('slug', 'Slug:')
$slugInput = $form->addText('slug', 'Slug:')
->addRule(Form::MinLength, 'Slug musí mít alespoň %d znaky', 3);
$this->validators->addValidateSlugRules($slugInput);
$this->addPublishedDate($form->addText('published', 'Vydáno:'))
->setDefaultValue(date('Y-m-d') . ' HH:MM');
$previewKeyInput = $form->addText('previewKey', 'Klíč pro náhled:')
Expand Down
4 changes: 3 additions & 1 deletion app/src/Form/TalkFormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

public function __construct(
private FormFactory $factory,
private FormValidators $validators,
private TrainingControlsFactory $trainingControlsFactory,
private Talks $talks,
private LinkGenerator $linkGenerator,
Expand All @@ -42,9 +43,10 @@ public function create(callable $onSuccess, ?Talk $talk = null): UiForm
$form->addSelect('locale', 'Jazyk:', $this->locales->getAllLocales())
->setRequired('Zadejte prosím jazyk')
->setPrompt('- vyberte -');
$form->addText('action', 'Akce:')
$actionInput = $form->addText('action', 'Akce:')
->setRequired(false)
->addRule(Form::MaxLength, 'Maximální délka akce je %d znaků', 200);
$this->validators->addValidateSlugRules($actionInput);
$form->addText('title', 'Název:')
->setRequired('Zadejte prosím název')
->addRule(Form::MaxLength, 'Maximální délka názvu je %d znaků', 200);
Expand Down
7 changes: 4 additions & 3 deletions app/src/Form/TalkSlidesFormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

public function __construct(
private FormFactory $factory,
private FormValidators $validators,
private TalkSlides $talkSlides,
private TexyFormatter $texyFormatter,
private SupportedImageFileFormats $supportedImageFileFormats,
Expand Down Expand Up @@ -96,9 +97,9 @@ private function addSlideFields(UiForm $form, Container $container, ?int $filena
$supportedImages = '*.' . implode(', *.', $this->supportedImageFileFormats->getMainExtensions());
$supportedAlternativeImages = '*.' . implode(', *.', $this->supportedImageFileFormats->getAlternativeExtensions());
$disableSlideUploads = (bool)$filenamesTalkId;
$container->addText('alias', 'Alias:')
->setRequired('Zadejte prosím alias')
->addRule(Form::Pattern, 'Alias musí být ve formátu [_.,a-z0-9-]+', '[_.,a-z0-9-]+');
$aliasInput = $container->addText('alias', 'Alias:')
->setRequired('Zadejte prosím alias');
$this->validators->addValidateSlugRules($aliasInput);
$container->addInteger('number', 'Slajd:')
->setDefaultValue(1)
->setHtmlAttribute('class', 'right slide-nr')
Expand Down
2 changes: 2 additions & 0 deletions app/src/lang/messages.cs_CZ.neon
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,5 @@ cookies:
netteSameSiteCheck: "Používá se pro detekci \"//same-site//\":[blog:co-znamena-origin-site-etld-etld-plus-1-public-suffix-a-psl#same-site] požadavků."
httpHeaders:
headerNotSent: "hlavička neposlána"
forms:
validateSlugParamsError: "%label musí odpovídat formátu %d"
2 changes: 2 additions & 0 deletions app/src/lang/messages.en_US.neon
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,5 @@ cookies:
netteSameSiteCheck: "Used to detect \"//same-site//\":[blog:origin-site-etld-etld-plus-one-public-suffix-psl-what-are-they#same-site] requests."
httpHeaders:
headerNotSent: "header not sent"
forms:
validateSlugParamsError: "%label must match %d"
52 changes: 52 additions & 0 deletions app/tests/Form/FormValidatorsTest.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
declare(strict_types = 1);

namespace MichalSpacekCz\Form;

use MichalSpacekCz\Test\TestCaseRunner;
use Nette\Forms\Controls\TextInput;
use Nette\Forms\Form;
use Tester\Assert;
use Tester\TestCase;

require __DIR__ . '/../bootstrap.php';

/** @testCase */
class FormValidatorsTest extends TestCase
{

public function __construct(
private readonly FormValidators $validators,
) {
}


public function getSlugs(): array
{
return [
['foo', true],
['foo-bar', true],
['foo-bar.baz', true],
['foo-bar,baz', true],
['foo-bar_baz', true],
['foo-bar-1337', true],
['foo/bar', false],
];
}


/** @dataProvider getSlugs */
public function testAddValidateSlugRules(string $slug, bool $result): void
{
$input = new TextInput();
$input->value = $slug;
$this->validators->addValidateSlugRules($input);
/** @noinspection PhpInternalEntityUsedInspection */
$input->setParent(new Form());
$input->validate();
Assert::same($result ? [] : ['messages.forms.validateSlugParamsError'], $input->getErrors());
}

}

TestCaseRunner::run(FormValidatorsTest::class);

0 comments on commit 55f3916

Please sign in to comment.