Skip to content

Latest commit

 

History

History
105 lines (76 loc) · 5.5 KB

custom_rules.md

File metadata and controls

105 lines (76 loc) · 5.5 KB

Vlastní pravidla

Úplně nejzákladnější funkcionalitou je přidání custom pravidla do formuláře nad rámec standardních Nette pravidel. To provedeme klasicky jako u Nette pravidel:

$container->addText('phone', '_label_phone')
	->setRequired()
	->addRule(\Pd\Forms\Rules::PHONE, '_msg_invalid_phone');

Toto pravidlo zavolá custom validátor z balíčku pd/utils: Pd\Utils\Validators::isPhone().

Dostupná custom pravidla v Pd\Forms

  • Pd\Forms\Rules::PHONE: validace formátu telefonního čísla
  • Pd\Forms\Rules::CONTAINS_NUMBER: validace inputu, zda-li obsahuje číslo (používá například u ulice)
  • Pd\Forms\Rules::ZIP: validace formátu PSČ
  • Pd\Forms\Rules::CZECH_COMPANY_IDENTIFIER: validace formátu českého (a slovenského) IČO
  • Pd\Forms\Rules::AJAX: obecná AJAXová validace

Vlastní pravidla a měkká / tvrdá validace

Vlastní pravidlo s měkkou validací se zaregistruje pomocí konstanty, jejíž obsah je callback na validátor. Dále si vytvoříme objekt Pd\Forms\RuleOptions pomocí továrny dostupné z balíčku pd/forms. Tovární služba je dostupná i pro formuláře vycházející z Pd\Base\Form, které se vytváří pomocí metody Pd\Base\Service::getForm(), v jiných use casech je možné si továrnu standardně vstříknout z DIC v konstruktoru.

$addressRuleOptions = $this->ruleOptionsFactory->createOptional();

$container->addText('address', '_label_address_form_address')
	->setRequired('_msg_address_form_address_required')
	->addRule(\Pd\Forms\Rules::CONTAINS_NUMBER, '_msg_pd_rule_contains_number_invalid', $addressRuleOptions);

Všimněte si kombinace nastavení setRequired() na inputu a createOptional() u custom pravidla. Toto nastavení zajistí, že je nutné vyplnit input pro adresu, nelze tedy odeslat prázdný input a navíc je na frontendu konkrolováno, jestli bylo do inputu zadáno číslo. Uživatel je na absenci čísla upozorněn, ale při odeslání adresy bez čísla je formulář odeslán = měkká validace.

V případě, kdy bychom chtěli, aby se formulář neodeslal dokud uživatel nevyplní k ulici číslo popisné, nepředali bychom vůbec objekt $ruleOptions nebo bychom jej předali jako povinný (což se využívá u složitejších validací (viz dále):

$addressRuleOptions = $this->ruleOptionsFactory->createRequired();

Vlastní validační pravidlo s kontextem

Vytvoření vlastního pravidla na backendu je poměrně jednoduché. Zaregistrujeme jej ideálně do třídy App\Forms\Rules následovně:

<?php declare(strict_types = 1);

namespace App\OrderModule\Forms;

final class Rules
{
	public const PPL_ALLOWED_ZIP = self::class . '::pplAllowedZip';


	public static function pplAllowedZip(\Nette\Forms\Controls\TextInput $textInput, \Pd\Forms\RuleOptions $options): bool
	{
		if ($options->isOptional()) {
			return TRUE;
		}

		return \App\OrderModule\Model\DeliveryMethods\DeliveryMethod::pplZipValidator((string) $textInput->getValue());
	}
}

Pokud plánujete, že pravidlo má být dostupné i pro měkkou validaci, je nutné zkontrolovat, jestli je pravidlo povinné v objektu \Pd\Forms\RuleOptions pomocí metody isOptional(). Pravidlo je zaregistrováno přes standardní Nette mechanismus, takže k vyhodnocení na backendu dochází vždy. Pokud se jedná o měkkou validaci, považuje se hodnota na backendu za vždy validní.

U některých validací se může objevit potřeba dodat validátoru sadu dat, proti kterým se bude hodnota formulářového pole validovat. Tato může být v čase proměnná, takže ji nelze hard kodóvat do validátoru. Taková data předáme pravidlu jako kontext.

$zipRuleOptions = $this->ruleOptionsFactory->createRequired()
	->addValidationMessage(\Pd\Forms\RuleOptions::STATUS_VALID, '_label_allowed_ppl_zip')
	->addContext('allowedPplZips', \App\OrderModule\Model\DeliveryMethods\DeliveryMethod::$allowedPPLZips)
;

$form->addText('zip')
    ->addCondition(\Nette\Forms\Form::FILLED)
        ->addRule(App\OrderModule\Forms\Rules::PPL_ALLOWED_ZIP, '_label_wrong_ppl_zip', $zipRuleOptions)
;

Data kontextu se serializují k inputu a můžete jak tak použít ve frontendovém validátoru. Na příkladu si také můžete všimnout, že na tyto custom validace lze využívat podmínky a větvení jak jste zvyklý ze standardních Nette pravidel. Krom toho je možné přidat hlášku, která se zobrazí v případě úspěšného zvalidování inputu (rozebereme více dále).

Na backendu je hotovo, nyní je potřeba k danému pravidlu vytvořit i frontendový validátor. Ten je potřeba zaregistrovat v projektovém pdForms.project.js, který by se měl do HTML vložit mezi netteForms.js (aby bylo nadefinované Nette.validators) a pdForms.js (aby v době inicializace již byla všechna pravidla nadefinována).

(function() {

	Nette.validators.AppOrderModuleFormsRules_pplAllowedZip = function(elem, arg, val) {
		if (typeof arg !== 'object' || typeof arg.context !== 'object' || typeof arg.context.allowedPplZips !== 'object') {
			return true;
		}

		var zip = parseInt(val.replace(/\s+/g, ''));

		for (var i = 0; i < arg.context.allowedPplZips.length; i++) {
			var rule = arg.context.allowedPplZips[i];
			if (rule.from <= zip && zip <= rule.to) {
				return true;
			}
		}

		return false;
	};

})();

Název JS validátoru (JS funkce) vychází z názvu konstanty definované v PHP třídě a z jejího kompletního FQN App\OrderModule\Forms\Rules::pplAllowedZip()AppOrderModuleFormsRules_pplAllowedZip.