Clicky

Skocz do zawartości


Zdjęcie
- - - - -

[K2] Formject - obsługa formularzy

4 odpowiedzi w tym temacie

  • Zaloguj się, aby dodać odpowiedź

#1 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 11 czerwiec 2012 - 10:58

Pracując nad własną wersją Kohany jednym z etapów prac było stworzenie modułu do obsługi formularzy. Dostępne w sieci moduły nie spełniały moich oczekiwań z racji pewnych braków/niedogodności, zatem postanowiłem napisać własny moduł.

Moduł przeznaczony jest pod Kohanę w wersji 2.3.4. Przy próbie uruchomienia go na "gołej" Kohanie wywali parę błędów. Dlatego też oprócz modułu formject zamieszczam moduł formject_extends. Zawiera ona kilka plików ze zmienionymi/dodanymi metodami. Można je przenieść do standardowej Kohany poprzez wyszukanie różnic między plikami za pomocą np. KDiff3. Do modułu tego dodałem również przykładowy kontroler (controllers/formject), dodatkową klasę własnego pola (libraries/CustomField) oraz widok dla tego pola (views/custom_field).

Moduł jest w fazie rozwojowej, wszelkie uwagi i sugestie mile widziane.

Poniżej zamieszczam kod przykładowego kontrolera:
<?php
// W standardowej wersji Kohany trzeba wczytać klasy ręcznie.
foreach (array(
'Formject/Element',
'Formject/Element/Container',
'Formject/Element/Field',
'Formject',
'Formject/Element/Container/Fieldset',
'Formject/Element/Field/Input',
'Formject/Element/Field/Password',
'Formject/Element/Field/Dropdown',
'Formject/Element/Field/Hidden',
'CustomField'
) as $file) {
require_once Kohana::find_file('libraries', $file);
}

class Formject_Controller extends Controller {
public function index() {
// Definicja pól formularza.
$form = new Formject();

$field = new Formject_Element_Field_Hidden('time');
$form->add_element($field);

$field = new Formject_Element_Field_Hidden('date');
$form->add_element($field);

$fieldset = new Formject_Element_Container_Fieldset('fieldset_1');
$fieldset->set_legend('Fieldset');
$form->add_element($fieldset);

$field = new Formject_Element_Field_Input('user.username');
$field
->set_label('Nazwa użytkownika')
->set_help('Adres e-mail')
->set_required(TRUE)
;
$fieldset->add_element($field);

$field = new Formject_Element_Field_Password('user.password');
$field
->set_label('Hasło')
->set_required(TRUE)
;
$fieldset->add_element($field);

$fieldset = new Formject_Element_Container_Fieldset('fieldset_2');
$fieldset
// Dodanie dodatkowych elementów.
->set_content_before_outside('Przed na zewnątrz')
->set_content_before_inside('Przed w środku')
->set_content_after_inside('Po w środku')
->set_content_after_outside('Po na zewnątrz')
;
$form->add_element($fieldset);

$field = new Formject_Element_Field_Dropdown('sex');
$field
->set_label('Płeć')
->set_options(array(
1 => 'mężczyzna',
2 => 'kobieta'
))
;
$fieldset->add_element($field);

// Nowe pole własnego typu.
// Klasa: formject_extends/libraries/CustomField
// Widok: formject_extends/views/custom_field
$field = new CustomField('custom');
$form->add_element($field);

$form->set_controllers(array(
form::submit(NULL, 'Go!')
));
//

// Wysłano formularz...
if (request::method() === 'post') {
// Wypełnienie danymi wysłanymi przez użytkownika.
$form->populate($this->input->post());

// Ustalenie reguł walidacji.
$form->get_validation()
->pre_filter('trim')
->add_rules('user.username', 'required', 'valid::email')
->add_rules('user.password', 'required', 'length[3,10]')
->add_rules('sex', 'required')
;

// Komunikaty błędów.
$errors = NULL; // Brak przekazania komunikatów błędów...
$errors = 'formject'; // ...lub z pliku tłumaczeń (i18n/en_US/formject.php)...
$errors = array( // ...lub w postaci tablicy.
'user' => array(
'username' => array(
'required' => 'Proszę podać nazwę użytkownika.',
'email' => 'Nazwa użytkownika powinna być adresem e-mail.'
)
),
'custom' => array(
'required' => 'Proszę wybrać co najmniej 1 strefę czasową.',
'validate_not_africa' => 'Nie możesz wybrać żadnej strefy czasowej z Afryki.'
)
);

// Formularz został wypełniony poprawnie...
if ($form->validate($errors)) {
print_r($form->get_values()); // Zwykła tablica.
print_r($form->get_values(FALSE)); // Tablica w notacji kropkowej.
var_dump($form->get_element_by_id('user.username')->get_value()); // Pobranie wartości konkretnego pola.

exit;
}
// ...lub błędnie.
else {
print_r($form->get_errors()); // Zwykła tablica.
print_r($form->get_errors(FALSE)); // Tablica w notacji kropkowej.
}
}
// ...lub ustawienie wartości domyślnych.
else {
// Wypełnienie formularza danymi w postaci tablicy...
$form->populate(array(
'time' => date('H:i:s')
));
// ...lub poprzez pobranie konkretnego pola.
$form->get_element_by_id('date')->set_value(date('Y-m-d'));
}

echo html::stylesheet('style.css');
echo $form;
}
}

oraz przykładową klasę własnego pola:
<?php
class CustomField extends Formject_Element_Field {
private $timezones = array();

// Ustawienie innego widoku.
protected $view = 'custom_field';

// Możliwość wyboru N elementów.
protected $multi_value = TRUE;

// Ustawiamy tablicę stref czasowych pogrupowanych według typu.
protected function init() {
foreach (timezone_identifiers_list() as $key => $item) {
$type = substr($item, 0, strpos($item, '/'));

if (!isset($this->timezones[$type])) {
$this->timezones[$type] = array();
}

$this->timezones[$type][$key] = $item;
}
}

// Zwracamy pola pogrupowane w listę.
// Można przenieść to do pliku widoku.
public function display() {
$value = $this->get_value();

$return = '<ol>';

foreach ($this->timezones as $type => $timezones) {
$return .= '<li>'.$type.'<ol>';

foreach ($timezones as $key => $item) {
$return .= '<li><label>'.form::checkbox($this->get_name(), $key, in_array($key, $value)).' '.$item.'</label></li>';
}

$return .= '</ol></li>';
}

$return .= '</ol>';

return $return;
}

// Ustawiamy reguły walidacji bezpośrednio w klasie pola.
// Będą aktywne dla wszystkich pól tego typu.
public function set_validation(Validation $validation) {
$validation->add_rules($this->get_id(), 'required', array($this, 'validate_not_africa'));
}

// Zabraniamy wyboru Afryki :)
public function validate_not_africa() {
foreach ($this->get_value() as $value) {
if ($value <= 50) {
return FALSE;
}
}

return TRUE;
}
}


Demo: http://kohana_2345.n...ero.pl/formject
Do pobrania: http://kohana_2345.n...pl/formject.zip
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#2 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 11 czerwiec 2012 - 12:01

Przejrzałem nieco pobieżnie, więc w razie czego nie bij ;)

Brakuje mi tu kilku rzeczy, m.in.:
- chainingu (wymaga magii, więc może nie być tak wydajnie, ale na pewno przyspiesza tworzenie formularzy),
- automatycznego populate'a,
- zintegrowanej walidacji (od razu przy tworzeniu pól),
- filtrów.


BTW. Przerabiałem ten temat niedawno, bo Formo nie dało się już rozszerzyć :)

#3 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 11 czerwiec 2012 - 12:27

Ok, więc po kolei:
1. Nie wiem czy o to Ci chodzi, ale metody ustawiające (set_*) zwracają $this. Samo utworzenie pełnego formularza jednym cięgiem chyba odpada z racji konieczności tworzenia obiektów poszczególnych pól.
2. Chodzi Ci o automatyczne wypełnianie na podstawie $_GET, $_POST i $_FILES? Jeśli tak to szczerze mówiąc nie widzę większego sensu robienia tego myku ;)
3 + 4. Domyślam się, że masz na myśli jakąś metodę na polu, np. $field->add_rules() czy $field->pre_filter(). Myślałem o tym i prawdopodobnie to wprowadzę. Pewnie będzie mały problem, bo obiekt $validation dostępny jest w obiekcie formularza, czyli pole samo z siebie nie ma do niego dostępu przed przypisaniem do kontenera.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#4 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 11 czerwiec 2012 - 12:56

1. Nie wiem czy o to Ci chodzi, ale metody ustawiające (set_*) zwracają $this. Samo utworzenie pełnego formularza jednym cięgiem chyba odpada z racji konieczności tworzenia obiektów poszczególnych pól.

Tak, o to mi chodzi. Przerabiałem to niedawno i jak najbardziej da się zrobić wszytko na raz, szybko i wygodnie ;)

2. Chodzi Ci o automatyczne wypełnianie na podstawie $_GET, $_POST i $_FILES? Jeśli tak to szczerze mówiąc nie widzę większego sensu robienia tego myku ;)

Imho to podstawa każdej biblioteki do formularzy. Sprawdzanie czy wysłany został post i wywoływanie populate() jest po prostu niewygodne. To powinno się ładować automatycznie przy uruchomieniu validate().

3 + 4. Domyślam się, że masz na myśli jakąś metodę na polu, np. $field->add_rules() czy $field->pre_filter(). Myślałem o tym i prawdopodobnie to wprowadzę. Pewnie będzie mały problem, bo obiekt $validation dostępny jest w obiekcie formularza, czyli pole samo z siebie nie ma do niego dostępu przed przypisaniem do kontenera.

W swojej bibliotece reguły i filtry przeniosłem do elementów formularza, sam kontener wywołuje tylko odpowiednie metody w elementach. Dodając walidator jako jeden z parametrów przekazuję komunikat (jeśli nie, to leci standardowy z i18n).


Generalnie tworząc bibliotekę starałem się jak najbardziej odwzorować interfejs Formo, żeby @nrm tworzący formularze raz na ruski rok mi nie płakał, że mu metody nie działają ;)

#5 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 11 czerwiec 2012 - 13:19

1. Zostawię to tak jak jest teraz, kosmicznie długie tasiemce jakoś nie wydają się dobrym rozwiązaniem.
2. No już nie przesadzajmy, że jest to aż tak upierdliwe ;)
3 + 4. Dodałem obsługę walidacji na poziomie pola. Reguły zapisuję do tablicy jako składowa pola, po czym przed odpaleniem walidacji przenoszę je do właściwego obiektu walidacji. Interfejs jest standardowy, czyli:
		$field = new Formject_Element_Field_Input('user.username');
$field
->set_label('Nazwa użytkownika')
->set_help('Adres e-mail')
->set_required(TRUE)
->add_rules('valid::digit', 'valid::date') // Nie ma to sensu, ale wiadomo o co chodzi ;)
->pre_filter('strip_tags')
;
$fieldset->add_element($field);

Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana




Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych