IPub\Phone – práce s tel. čísly ve formulářích, šablonách a databázích jednoduše

akadlec
Člen | 1326
+
+10
-

IPub\FormPhone

Pokud ve formulářích řešíte získání tel. čísla od vašeho návštěvníka/klienta, víte že to je občas docela problém, každý jej zadává jak se mu zlíbí a jeho validace je docela problematická. A tak jsem vytvořil formulářový element který je založený na další knihovně IPub\Phone

Práce s touto extension je velice jednoduchá. Stačí si extension zaregistrovat (pokud chcete využívat všechny její featurky) a pak jednoduše vložit element pro vložení tel. čísla:

$form = new Nette\Application\UI\Form;

$form
	->addPhone('phone_number', 'Your phone number');

Element samozřejmě disponuje i vlastním validátorem. Chcete-li omezit možnost zadání čísla jen na vybrané země, stačí je specifikovat:

$form = new Nette\Application\UI\Form;

$form
	->addPhone('phone_number', 'Your phone number')
	->addRule(FormPhone\Forms\PhoneValidator::PHONE, 'Invalid phone.')
	->setAllowedCountries(['CZ', 'SK', 'PL']);

Případně se dá také udělat validace na typ tel. čísla jako je pevná linka, mobil apod.

$form = new Nette\Application\UI\Form;

$form
	->addPhone('phone_number', 'Your phone number')
	->addRule(FormPhone\Forms\PhoneValidator::PHONE, 'Invalid phone.')
	->setAllowedPhoneTypes(['mobile', 'fixed_line']);

Když se pole pro tel. číslo vykreslí ve formuláři, je tvořeno dvěmi políčky – jedno je select pro výběr země a tedy mezinárodního předčíslí a pak samotné číslo.

K dispozici je taky klientská část s JS validací, stačí přilinkovat patřičné JS soubory a to je vše. Kromě JS validace je v JS taky dostupná maska, tj. input box pro zadání čísla se vám naformátuje podle zvolené země, takže pro ČR to bude 234 456 789 tedy s mezerami mezi 3číslí

IPub\Phone

Tato knihovna je jakýmsi jádrem pro všechny knihovny pracujícím z tel. číslem. Implementuje PHP portGooglí knihovny.

Práce s touto extension je docela jednoduchá. Hlavní prvek je vytvoření entity ze zadaného čísla, a tak z čísel co máte v DB máte možnost vytvořit validní čísla, případně zjistíte že čísla jsou nevalidní.

$phoneNumber = IPub\Phone\Entities\Phone::fromNumber($numberFromDB, $countryOrNothing);

V $phoneNumber pak budete mít entitu nesoucí informace o tel. čísle a to včetně naformátované hodnoty pro národní i mezinárodní zobrazení.

Další funkcionalitou je validátor pro formuláře. Pokud nechcete používat rozšíření pro formuláře zmíněné výše, ale chcete jen validátor, je to jednoduché, stačí jej vložit do textového pole:

$form = new Nette\Application\UI\Form;

$form
    ->addText('phone_number', 'Your phone number')
    ->addRule(Phone\Forms\PhoneValidator::PHONE, 'Invalid phone.', ['GB', 'US', 'CZ']);

Celá validace je pak postavena na tom, že uživatel musí zadat číslo celé jak po něm chcete. Pokud tedy chcete mít možnost zadat libovolné číslo, tak nastavíte automatickou detekci a pokud uživatel nevyplní číslo v mezinárodním formátu tak mu zobrazíte hlášku. Pokud víte že čísla budou jen CZ a SK tak si zvolíte tyto země a tady už může být číslo zadáno zkráceně…o dalších možnostech a nastaveních se pak samozřejmě dočtete v malém quick startu

K dispozici je taky klientská část s JS validací, stačí přilinkovat patřičné JS soubory a to je vše.

Pokud nechcete jen validovat formuláře ale s číslem i dále pracovat, je zde k dispozici i malý helper a macro pro latte

IPub\DoctrinePhone

No a pokud ve svých projektech využíváte Doctrinu tak je pro vás připravena knihovna co rozšíří doctríní datové typy o telefonní číslo a tak když v entitě načtete tel. číslo, bude přetvořeno na objekt nesoucí kompletní informace o čísle a stejně tak jej můžete entitě předat a ta se pak pomocí událostí postará o jeho korektní uložení v mezinárodním formátu tak aby bylo možne jej vždy bez problému rozparsovat.

Kdyby někoho napadlo jak to třeba vylepšit či udělat něco jinak, tak klidně napište.

Editoval akadlec (31. 12. 2015 10:44)

akadlec
Člen | 1326
+
0
-

Mohl by nějaký admin změnit název tohoto topicu? Trošku jsem to přepracoval a rozšířil a je z toho soubor 3 doplňků a nechtělo se mě zakládat pro každý vlastní topic.

Aurielle
Člen | 1281
+
0
-

Vypadá to výborně, a pro změnu názvu bych zkusil pingnout třeba @FilipProcházka nebo @DavidMatějka :)

David Matějka
Moderator | 6445
+
0
-

zmenim, na co presne? :)

akadlec
Člen | 1326
+
0
-

Třeba na: IPub\Phone – práce s tel. čísly ve formulářích, šablonách a databázích jednoduše :D

E: dík ;)

Editoval akadlec (1. 1. 2016 11:54)

sucho
Člen | 57
+
0
-

Ahoj vyzerá to pekne skúšal som to integrovať

ale pri SK krajine vyzerá tá maska dosť zle na mobilnom čísle
stále to ponúka ako pevnú linku v tvare __/___ ___ __

skúšal som meniť aj AllowedPhoneTypes na rôzne aj EMERGENCY a žiadna zmena v SK maske

$form->addPhone('phone', _('Telefón'))
		->setAllowedCountries(['CZ', 'SK'])
		->setAllowedPhoneTypes([\IPub\Phone\Phone::TYPE_MOBILE])
		->addCondition(UI\Form::FILLED)
		->addRule(\IPub\FormPhone\Forms\PhoneValidator::PHONE, _('Zadajte telefónne číslo v správnom formáte'));

povezme že máme mobilné číslo 0901 234 567
a ono to prerobí na 09/012 345 67 alebo 90/123 456 7_
správne po výbere krajiny by malo byť (v selecte +421) a (v inpute 901 234 567)

chcem sa opýtať či o masku sa stará ipub/form-phone alebo giggsey/libphonenumber-for-php
a ako by sa to dalo vyriešiť

Editoval sucho (1. 2. 2016 10:16)

akadlec
Člen | 1326
+
0
-

Maska je JS činnost, tam se to nastavuje jen podle země, pokud tedy máš namysli jen to zobrazení v inputu.

F.Vesely
Člen | 369
+
0
-

Doplnek vypada moc pekne, funguje az na jednu chybku. Pokud mam

$form->addPhone('phone')
	->addCondition(Form::FILLED)
		->addRule(PhoneValidator::PHONE, 'Enter valid telephone.');

tak mi nefunguje JS validace, protoze addCondition() dava do data-nette-rules jako control [phone] a ne [phone][number].

akadlec
Člen | 1326
+
0
-

@sucho Hele pro SK a případně jiné krajiny to bude asi dělat problémy protože ten pattern se dělá ze vzorového čísla a to vzorové číslo generuje giggseyho knihovna. Leda by js mělo svou vlastní kolekci patternů jednotlivých čísel pro jednotlivé země.

Kaliver
Člen | 12
+
0
-

@akadlec Myslim, ze vzorove cislo momentalne generujes cez getExampleNumber() v giggseyho kniznici. Ta vsak prebera len $regionCode a nasledne je tam natvrdo nastaveny type FIXED LINE.

public function getExampleNumber($regionCode)
    {
        return $this->getExampleNumberForType($regionCode, PhoneNumberType::FIXED_LINE);
    }

Takze tvoj script bude fixne v pripade SK nastavovat masku pre pevnu linku. Nechcel by si to upravit, tak ze by si vyuzil funkciu getExampleNumberForType() ?

Editoval Kaliver (17. 2. 2016 11:29)

akadlec
Člen | 1326
+
0
-

Jestli máš možnost tak k tomu pošli PR, já nevím kdy se k tomu teď dostanu.

Landsman
Člen | 152
+
0
-

Možná něco dělám blbě, ale po přidání do composer + přidání extension mi nette vyhazuje:

Service '' not found.
IPub\FormPhone\Controls\Phone::register($this->getService(NULL));

akadlec
Člen | 1326
+
0
-

A registroval sis ext. ipub/phone?

potapnik
Člen | 127
+
0
-

Me to dela totez, extension registrovana.

akadlec
Člen | 1326
+
0
-

obě? Protože tohle je chyba pokud není registrována extension IPub\Phone

Landsman
Člen | 152
+
0
-

akadlec napsal(a):

obě? Protože tohle je chyba pokud není registrována extension IPub\Phone

To musíš přidat 2 extension? Proč?
Nakonec jsem to vyřešil jednodušeji: http://jsfiddle.net/dKRGE/3/

akadlec
Člen | 1326
+
0
-

@F.Vesely hele nevim jak to zkoušíš, ale mě ta validace funguje ok. Můžeš když tak gist či příklad někde?

@Kaliver hele doplnil sem možnost generovat example number zvoleného typu. Jen to asi nebude řešit tvůj problém v JS kde se ty templaty generujou ze selectu země. Leda by se pro SK generovaly dvě verze předčíslí :(

@Landsman Proč 2 extension? No jednoduše proto, protože jedna rozšiřuje druhou. IPub/Phone je jádro, má v sobě veškerou funcionalitu práce s číslem a k tomu je jako doplněk IPub/FormPhone co ti do formu přináší možnost jednoduše implementovat zadávání tel. čísla. Netuším cos řešil, ale to cos postnul v jsfiddle je úplně něco jiného než řeší tahle sada doplňků. To tvoje je jen primitivní input maska pole, nikoliv validace že zadané číslo je ok a je reálné.

PS: Všem sorry za poněkud delší odmlku :)

PSS: Všechny tři doplňky prošly refactorem a pojedou vám v nejnovějším nette 2.4. Enjoy ;)

spagi
Člen | 5
+
0
-

@akadlec je nejaky zpusob jak pridam to toho prvku css tridu?
Dik

akadlec
Člen | 1326
+
0
-

Myslíš do inputu co generuje ipub/form-phone? Pokud jo a generuješ form automaticky přes nette, tak aktuálně nijak. Pokud děláš ruční render tak pak přímo v šabloně:

{input phones-number:number class => 'my-class'}

Já osobně nemám rád nastavování CSSek v phpku tak sem to tam nedal, ale teoreticky by to šlo dodělat, nějaký setter co bude přidávat atributy generovanému inputu.

spagi
Člen | 5
+
0
-

ok dik za info

lvq
Člen | 47
+
0
-

@akadlec Ahoj, je možné používat rozšíření do Doctrine s tím, že tel. číslo může být NULL. Když do anotace napíšu:

	/**
	 * @var Phone|null
	 * @ORM\Column(type="phone", nullable=TRUE)
	 */
	private $phone;

tak to nepomáhá.
Díky

MartinS
Člen | 2
+
0
-

Ahoj,
je možné docílit html5 validního prvku? Je pravda že id „frm-registerForm-registerProfileFactoryForm-phone“ neexistuje.
Html Error: The „for“ attribute of the „label“ element must refer to a non-hidden form control

<div class="form-group">
	<label for="frm-registerForm-registerProfileFactoryForm-phone">Telefonní číslo:</label>

	<select name="phone[country]" id="frm-registerForm-registerProfileFactoryForm-phone-country" data-ipub-forms-phone="" data-settings='{"field":"phone[number]"}'><option data-mask="999 999 999" value="CZ">+420 (Česká republika)</option></select><input name="phone[number]" id="frm-registerForm-registerProfileFactoryForm-phone-number" type="text" class="form-control" data-nette-empty-value="" data-nette-rules='[{"op":"optional"},{"op":":filled","rules":[{"op":"IPub\\FormPhone\\Forms\\PhoneValidator::validatePhone","msg":"Zadejte platné telefonní číslo."}],"control":"phone"}]'>
</div>
akadlec
Člen | 1326
+
0
-

@MartinS : ok požadavek zapracován. Nyní má label IDčko inputu pro číslo

sten192
Člen | 2
+
0
-

Ahoj, rozsirenie som sa pokusal instalovat podla navodu na GtHube.

V config.neon mam nasledovne riadky (extensions):

phone: IPub\Phone\DI\PhoneExtension
formPhone: IPub\FormPhone\DI\FormPhoneExtension

Nette mi vsak vyhadzuje nasledovnu chybu:

Strict standards
Declaration of IPub\FormPhone\Controls\Phone::getControlPart() should be compatible with Nette\Forms\Controls\BaseControl::getControlPart()

V com moze byt problem? Pouzivam Nette 2.4

akadlec
Člen | 1326
+
0
-

v tom že máš 2.4ku :D

sten192
Člen | 2
+
0
-

Aha, jasne :D. Planujes rozsirit podporu aj na tuto verziu?

F.Vesely
Člen | 369
+
0
-

Ve verzi pro PHP 7 je to opravene.

CZechBoY
Člen | 3608
+
0
-

@F.Vesely v masteru teda ne

CZechBoY
Člen | 3608
+
0
-

@F.Vesely No, tam chybí ten návratovej typ, ne?

https://3v4l.org/AF3NI

Editoval CZechBoY (15. 8. 2017 16:42)

cafesk8
Člen | 103
+
0
-

Zdravím,

při vložení ipub.formPhone.js mi console píše chybovou hlášku $(...).ajaxSuccess is not a function na řádku 481:

// Autoload for ajax calls
$(document).ajaxSuccess(function () {
    // Autoload plugin
    IPub.Forms.Phone.load();
});

Místo nette.ajax.js používám v projektu Naja.js.
Skripty mám vložené následovně:

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>
<script src="https://nette.github.io/resources/js/netteForms.min.js"></script>
<script src="/assets/js/Naja.js"></script>
<script src="/assets/js/ipub.formPhone.js"></script>
<script src="/assets/js/live-form-validation.js"></script>
<script src="/assets/js/app.js"></script>

Nevíte v čem by mohl být problém?

Díky

Editoval cafesk8 (19. 6. 2018 12:03)

rkor
Člen | 62
+
+1
-

jquery.slim nemá podporu pro ajax

cafesk8
Člen | 103
+
0
-

rkor napsal(a):

jquery.slim nemá podporu pro ajax

Super, bylo to tím, díky.

cafesk8
Člen | 103
+
0
-

Ještě jsem se chtěl zeptat, když mám povolené tel. ve formátu pouze pro ČR: setAllowedCountries(['CZ']), je možné v konfiguraci nebo něčím schovat selectbox, který ztrácí význam, když není z čeho vybírat? Nebo to budu muset udělat prasácky přes CSS?

cafesk8
Člen | 103
+
0
-

Zdravím,

mám ajaxový formulář, kde mám přidané povinné pole pro české telefonní číslo. Celé to vypadá takto:

protected function createComponentNewWhatever()
{
    $form = new Nette\Application\UI\Form;
    $form->setRenderer(new \AlesWita\FormRenderer\BootstrapV4Renderer);
    $form->getElementPrototype()->class = 'ajax';
    $form->addProtection('Vypršel časový limit, odešlete formulář znovu');

		# zde je ještě spousta dalších prvků formuláře

  	$form->addPhone('nv_telefon', 'Telefon:')
    	->setAllowedCountries(['CZ'])
    	->addRule(\IPub\FormPhone\Forms\PhoneValidator::PHONE, 'Musíte zadat platné tel. číslo.')
    	->setRequired('Musíte zadat Vaše tel. číslo.');


    $form->addSubmit('nv_submit', 'Přidat vozidlo');

    $form->onSubmit[] = [$this,'handleZkontrolujForm'];
    $form->onSuccess[] = [$this,'handleNewWhatever'];

    return $form;
	}

public function handleZkontrolujForm(Form $form)
	{
    if ($this->isAjax()) {
        $this->redrawControl('formSnippet');
    }
}

	public function handleNewWhatever(Form $form)
{
    $this->flashMessage('Úspěšně přidáno.','success');
    $form->reset();

    if ($this->isAjax()) {
        $this->redrawControl('formSnippet');
        $this->redrawControl('flashes');
    }
}

Vše mi fungovalo, včetně live validace apod. Problém nastal až při přidání pole pro telefon. Při načtení se mi krásně načte pole kde jsou — --- — pro vyplnění tel. čísla. Problém nastane až poté, co formulář odešlu. Ať již je číslo validní a formulář se vyresetuje a zobrazí se success flash message, či nikoliv (např. 123 456 789) a zobrazí se hláška, že musím vyplnit platné tel. číslo, tak mi z pole zmizí takový ten placeholder — --- — a můžu do pole zadávat jakékoliv znaky a také jakýkoliv počet znaků.

Nevíte někdo v čem by mohl být problém?

akadlec
Člen | 1326
+
0
-

Ad select, tahle featura tam neni, ale mohla by se dodělat.
Ad js formátování čísel, problém je v JS. Když se ti form načte napoprvé klasickým requestem, tak se spustí potřebný JS který aktivuje formátování. Když ale uděláš ajaxový request, tak dojde k překreslení DOMu kde máš právě ten input, ale už se znova nezavolá. Řešením je abys v onSuccess metodě toho ajaxu znova initnul JS pro tel. číslo. Samotné řešení je pak na tom jak máš ty JS řešeny. Jedno z nich může být takové že si udělat extension pro nette ajax (pokud jej používáš) která bude dělat ten init po onSuccess

cafesk8
Člen | 103
+
0
-

akadlec napsal(a):

Ad select, tahle featura tam neni, ale mohla by se dodělat.
Ad js formátování čísel, problém je v JS. Když se ti form načte napoprvé klasickým requestem, tak se spustí potřebný JS který aktivuje formátování. Když ale uděláš ajaxový request, tak dojde k překreslení DOMu kde máš právě ten input, ale už se znova nezavolá. Řešením je abys v onSuccess metodě toho ajaxu znova initnul JS pro tel. číslo. Samotné řešení je pak na tom jak máš ty JS řešeny. Jedno z nich může být takové že si udělat extension pro nette ajax (pokud jej používáš) která bude dělat ten init po onSuccess

Díky za odpověď, select si zatím pouze schovám a JS jsem vyřešil takto, třeba to někomu v budoucnu pomůže (používám Naja.js namísto nette.ajax.js):

function LoaderExtension(naja) {
    naja.addEventListener('complete', reInitPhone.bind(this));

    function reInitPhone() {
        IPub.Forms.Phone.load();
    }
    return this;
}
naja.registerExtension(LoaderExtension);

document.addEventListener('DOMContentLoaded', naja.initialize.bind(naja));

Zajímavé je, že v JS pluginu je už a nefungovalo to (asi to bude tím, že Naja.js oproti nette.ajax.js nemá funkci ajaxSuccess ?):

// Autoload plugin
IPub.Forms.Phone.load();

// Autoload for ajax calls
$(document).ajaxSuccess(function () {
    // Autoload plugin
    IPub.Forms.Phone.load();
});

Editoval cafesk8 (20. 6. 2018 9:25)

akadlec
Člen | 1326
+
0
-

:+1: