Form live validace – pojmenované/anonymní funkce/statické metody

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
2bad2furious
Člen | 26
+
0
-

Ahoj,
co je podle Vás ideální způsob custom validace? Potřebuji některé věci dělat na frontendu, to by chtělo buď pojmenované nebo statické funkce(kvůli snadnému přístupu v js). Zároveň však na backendu potřebuji přístup k různým službám přímo v presenteru, proto se zas hodí anonymní funkce nebo funkce samotného presenteru, protože pojmenované nemohou mít kontext($variables použitelné mimo funkci). Je možné, že se někde pletu, ocením každou radu.

Uvádím příklad:

$form->addText(UserManagement::USERNAME, UserManagement::USERNAME_LABEL)
           ->setRequired(UserManagement::USERNAME_REQUIRED)
           ->addRule(Form::MIN_LENGTH, UserManagement::USERNAME_MIN_LENGTH_TEXT, UserManagement::USERNAME_MIN_LENGTH)
           ->addRule(function (\Nette\Forms\Controls\TextInput $username) {
               return $this->getUserManager()->isUsernameOk($username->getValue());
           }, UserManagement::USERNAME_ALLOWED_CHARS)
           ->addRule(function (\Nette\Forms\Controls\TextInput $username) {
               return $this->getUserManager()->isUsernameUnique($username->getValue());
           }, UserManagement::USERNAME_EXISTS)
           ->addRule(Form::MAX_LENGTH, UserManagement::USERNAME_MAX_LENGTH_TEXT, UserManagement::USERNAME_MAX_LENGTH);
matopeto
Člen | 395
+
+1
-

Ja osobne mam anonymne funkcie rad – pokial su rychle jednoduche a velakrat sa neopakuju. Inak by som si vytvoril validator. Ak sa uz ale pouzivaju na viac miestach je dobre ich oddelit. Na jednoduche pouzivam staticke metody. Na zlozitejsie… zalezi aky kontext potrebujes, pokial je kontext nejake services tak validator predaj ako DI, ktory bude mat cez DI svoje zavislosti. Pripadne mozes pouzit kombinaciu, kde zavolas anonymnu funkciu v ktorej zavolas instancnu metodu nejakeho nestatickeho validatora s potrebnymi parametrami – tak ako to mas vo svojom priklade :) Moznosti je samozrejme niekolko.

Editoval matopeto (4. 8. 2017 15:39)

2bad2furious
Člen | 26
+
0
-

Díky za odpověď. Spíš mě to trápí v kombinaci s validací v js. Nebyl problém dát do js něco jako

<script>
Nette.validators.checkUsername = function (elem, args, val) {
    return !(new RegExp(/[^0-9a-zA-Z-_+]/).test(val));
}
</script>

Jak se tohle udělá s anonymními funkcemi? Osobně bych ocenil kdyby ->addRule([$this,„nazevMetody“],…) se přidalo do elementu taky třeba s názvem validátoru „nazevMetody“ a v js bych už věděl, jak si s tím jednoduše poradit, + by to nutilo k čistějšímu kódu)

--
Ukážeš prosím příklad toho validátoru s DI?

Editoval 2bad2furious (4. 8. 2017 16:06)

matopeto
Člen | 395
+
0
-

Priklad validatoru s DI mas v tom svojom

`getUserManager' je validator ktoreho zavislosti su predane cez DI.

Ci to uz zavolas priamo addRule([$this->getUserManager, "isUsernameUnique"], ... alebo az v anonymnej funkcii je to jedno.

S tym javascriptom neporadim to som neriesil nikdy

Na ten jednoduchy regex nepotrebujes anonymnu funkciu staci ti ->addRule(Form::PATTERN, "blablabla", "[0-9a-zA-Z-_+]+")

Edit: jasne uz chapem, tie js funguju tak ze pokial ten rule je nazov lokalnej metody, tak sa to prenesie do js, a s anonymnymi funkciami ani s objektovym volanim to ako vravis asi nejde. Hm…

Editoval matopeto (4. 8. 2017 16:31)

matopeto
Člen | 395
+
0
-

Pokial chces zistit preco sa ti to do js negeneruje alebo ako to cele funguje (co sam by som si musel nastudovat), pripadne si to upravit tak ako to by si to chcel… je to na tomto mieste:

https://github.com/…/Helpers.php#L95

Tam vidno ze do javascriptu/html sa bohuzial prepisuju iba staticke a stringove validatory, ale upravit to nebude asi problem. Ale zasahovat do nette niez nie je asi dobry napad :(

Editoval matopeto (4. 8. 2017 16:50)

CZechBoY
Člen | 3608
+
+1
-

Zasahovat ne, ale poslat PR je ;-)

2bad2furious
Člen | 26
+
0
-

Dal jsem to jako issue, nechám řešení na nich. https://github.com/…s/issues/163

2bad2furious
Člen | 26
+
0
-

matopeto napsal(a):

Priklad validatoru s DI mas v tom svojom

`getUserManager' je validator ktoreho zavislosti su predane cez DI.

Ci to uz zavolas priamo addRule([$this->getUserManager, "isUsernameUnique"], ... alebo az v anonymnej funkcii je to jedno.

S tym javascriptom neporadim to som neriesil nikdy

Na ten jednoduchy regex nepotrebujes anonymnu funkciu staci ti ->addRule(Form::PATTERN, "blablabla", "[0-9a-zA-Z-_+]+")

Edit: jasne uz chapem, tie js funguju tak ze pokial ten rule je nazov lokalnej metody, tak sa to prenesie do js, a s anonymnymi funkciami ani s objektovym volanim to ako vravis asi nejde. Hm…

~Form::PATTERN je deprecated, přes pozitivní regex to čekuje opačně. Potřebuji zjistit, zda tam jsou nějáké nevhodné znaky a potom ukázat error.

CZechBoY
Člen | 3608
+
0
-

No musíš udělat whitelist, tzn. výraz kterým projde tvůj požadovaný formát.

$input->addRule(Form::PATTERN, co musí řetězec splňovat);
matopeto
Člen | 395
+
0
-

2bad2furious napsal(a):

matopeto napsal(a):

Priklad validatoru s DI mas v tom svojom

`getUserManager' je validator ktoreho zavislosti su predane cez DI.

Ci to uz zavolas priamo addRule([$this->getUserManager, "isUsernameUnique"], ... alebo az v anonymnej funkcii je to jedno.

S tym javascriptom neporadim to som neriesil nikdy

Na ten jednoduchy regex nepotrebujes anonymnu funkciu staci ti ->addRule(Form::PATTERN, "blablabla", "[0-9a-zA-Z-_+]+")

Edit: jasne uz chapem, tie js funguju tak ze pokial ten rule je nazov lokalnej metody, tak sa to prenesie do js, a s anonymnymi funkciami ani s objektovym volanim to ako vravis asi nejde. Hm…

~Form::PATTERN je deprecated, přes pozitivní regex to čekuje opačně. Potřebuji zjistit, zda tam jsou nějáké nevhodné znaky a potom ukázat error.

Ale tvoj pattern je pozitivny :) i ten negativny javascriptovy potom negujes :) neni problem ale napisat regex co splnuje opak i bez negacie…

->addRule(Form::PATTERN, "blablabla", "[0-9a-zA-Z-_+]+")

znamena ze filed musi obsahovat iba cisla pismena -+_ chces checkovat iba nepovolene znaky? tak sprav skorej regex na povolene… nevude to nic zlozite

Editoval matopeto (5. 8. 2017 22:45)

2bad2furious
Člen | 26
+
0
-

Díky, regex se tady nemusí obalovat delimiterama?
Jinak nějaký nápad jak vylepšit toto? Mozilla upozorňuje, že synchronní dotaz je starej.

<script>
checkAvailability = function (type, val) {
    if (typeof type !== "string" || typeof val !== "string")
        throw new Error("wrong parameters passed");
    if (type !== "email" && type !== "username")
        throw new Error(type + " is probably not supported");

    response = new AvailabilityResponse(-2, "");

    $.ajax({
        url: "/api/check-availability/" + type + "/",
        data: {
            "value": val
        },
        async: false,
        method: "POST",
        success: function (r) {
            response = new AvailabilityResponse(r.status, r.message);
            return response;
        },
        error: function (r) {
            response = new AvailabilityResponse(-2, "");
        }
    })
    var status = response.getStatus();
    if (status === -1 || status === -2) {
        console.info("something went wrong while checking " + type)
        return true;
    }
    return (status === 1);
}
</script>
matopeto
Člen | 395
+
0
-

mas tam async false, to nepouzivaj, nepotrebujes to. Nevracaj si true ale false, ale funkcii predaj success a error callback, pripadne jeden resultCallback, s bool parametrom true/false pripadne s tvojim AvailabilityResponse, ktory sa ti zavola v odpovedi a spracujes si to asynchronne. Na chceckovanie dostupnosti mena ziadnu synchronnost nepotrebujes.

Pattern nevyzaduje delimiters, doplnuje ich tam sam.

Editoval matopeto (6. 8. 2017 10:53)

2bad2furious
Člen | 26
+
0
-

matopeto napsal(a):

mas tam async false, to nepouzivaj, nepotrebujes to. Nevracaj si true ale false, ale funkcii predaj success a error callback, pripadne jeden resultCallback, s bool parametrom true/false pripadne s tvojim AvailabilityResponse, ktory sa ti zavola v odpovedi a spracujes si to asynchronne. Na chceckovanie dostupnosti mena ziadnu synchronnost nepotrebujes.

Pattern nevyzaduje delimiters, doplnuje ich tam sam.

Jsem trochu zmaten z tvé odpovědi. Jak by jsi řešil tento konkrétní případ?

<script>
checkAvailability = function (type, val) {
    if (typeof type !== "string" || typeof val !== "string")
        throw new Error("wrong parameters passed");
    if (type !== "email" && type !== "username")
        throw new Error(type + " is probably not supported");

    var status = -2;

    $.ajax({
        url: "/api/check-availability/" + type + "/",
        data: {
            "value": val
        },
        async: false,
        method: "POST",
        success: function (r) {
            status = r.status;
        },
        error: function (r) {
            status = -2;
        }
    })
    if (status === -1 || status === -2) {
        console.info("something went wrong while checking " + type)
        return true;
    }
    return (status === 1);
}


/**
 * @return {boolean}
 */
Nette.validators.username_rule3 = function (elem, args, val) {
    return checkAvailability("username", val);
}
</script>
matopeto
Člen | 395
+
0
-

Toto uz cez nette validators neurobis, musis si tu validaciu urobit sam.

Pseudokod:

function checkAvailability(username, value, result) {
	$.ajax(...
		success: function(r) {
			result(r.status);
		},
		error: function() {
			result(-2);
		});
}

// Potom niekde ked to chces checkovat, napr `onblur` na username inpute.

username.addEventListener('blur', function() {
	checkAvailability('username', username.value, function(status) {
		if (status === 1) {
			showOkMark(); // pripadne cokolvek co chces aby sa stalo alert, error stav a tak...
		} else if (status === 2) {
			showNotOkMark();
            // mozno pojde zavolat nieco take Nette.addError(username, "message"); ale to treba skusit...
		}

	});
});

Editoval matopeto (6. 8. 2017 11:52)

2bad2furious
Člen | 26
+
+1
-

Díky za pomoc.
Moje řešení pro budoucí badatele:
(Lepší řešení by bylo dostání té původní message z html a zabránění přidání classy „has-success“, pokud máte showValid:true)

<script>
checkAvailability = function (type, val, elem) {
    if (typeof type !== "string" || typeof val !== "string")
        throw new Error("wrong parameters passed");
    if (type !== "email" && type !== "username")
        throw new Error(type + " is not supported");

    $.ajax({
        url: "/api/check-availability/" + type + "/",
        data: {
            "value": val
        },
        method: "POST",
        success: function (r) {
            console.info(r, typeof r.status !== "undefined", r.status === 0);
            if (typeof r.status !== "undefined" && r.status === 0) {
                LiveForm.addError(elem, r.message)
            }
        },
        error: function () {
            console.info("There was en error while checking " + type)
        }
    })
}


/**
 * @return {boolean}
 */
Nette.validators.username_rule3 = function (elem, args, val) {
    checkAvailability("username", val, elem);
    return null;
}

/**
 * @return {boolean}
 */
Nette.validators.email_rule2 = function (elem, args, val) {
    checkAvailability("email", val, elem);
    return null;
};
</script>