Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [klasa] Klasa walidująca dane (ze zmiennych)
Forum PHP.pl > Inne > Oceny
in5ane
Hej, chce poddać ocenie swoją klasę walidującą dane. Powiedzcie, co jest dobrze, a co źle. Co do robić, co przerobić. Proszę o opinie smile.gif

  1. <?php
  2.  
  3. /**
  4.  * Class data validation (can be used to form validation)
  5.  *
  6.  * Class data validation (can be used to form validation).
  7.  * Here is an example usage and available parameters.
  8.  * Example of use: $formValidation->validate($pass, "required|matches[$pass_c]|min_length[6]");
  9.  * Possible parameters to use:: required, numeric, matches[comparison], min_length[number], max_length[number], exact_length[number], valid_email
  10.  *
  11.  * @version 1.0
  12.  * @author Jakub Kubera <jakubkubera1992@gmail.com>
  13.  * @link www.jakubkubera.pl
  14.  * @license New BSD License
  15.  * @access public
  16.  */
  17. class ValidationData
  18. {
  19.  
  20. private $name;
  21. private $rules = array();
  22.  
  23. /**
  24.   * Assigning parameters to the class variables and run validation
  25.   *
  26.   * @param string $name Field name
  27.   * @param string $rules Field validation rules
  28.   *
  29.   * @return bool Returns whether validation was successful
  30.   */
  31. public function validate($name, $rules)
  32. {
  33. $this->name = $name;
  34.  
  35. $this->explodeRules($rules);
  36.  
  37. return $this->run();
  38. }
  39.  
  40. /**
  41.   * Returns whether validation was successful
  42.   *
  43.   * @return bool Returns whether validation was successful
  44.   */
  45. private function run()
  46. {
  47. $errors = array();
  48.  
  49. if (in_array('required', $this->rules))
  50. if ($this->checkRequired() === false)
  51. $errors[] = 'required';
  52.  
  53. if (in_array('numeric', $this->rules))
  54. if ($this->checkNumeric() === false)
  55. $errors[] = 'numeric';
  56.  
  57. if ($key = $this->pregArrayKey('/matches\[(.*)]/'))
  58. {
  59. preg_match('/\[(.*)]/', $this->rules[$key], $confirm);
  60. if ($this->checkMatches($confirm[1]) === false)
  61. $errors[] = $this->rules[$key];
  62. }
  63.  
  64. if ($key = $this->pregArrayKey('/min_length\[(.*)]/'))
  65. {
  66. preg_match('/\[(.*)]/', $this->rules[$key], $value);
  67. if ($this->checkMinLength($value[1]) === false)
  68. $errors[] = $this->rules[$key];
  69. }
  70.  
  71. if ($key = $this->pregArrayKey('/max_length\[(.*)]/'))
  72. {
  73. preg_match('/\[(.*)]/', $this->rules[$key], $value);
  74. if ($this->checkMaxLength($value[1]) === false)
  75. $errors[] = $this->rules[$key];
  76. }
  77.  
  78. if ($key = $this->pregArrayKey('/exact_length\[(.*)]/'))
  79. {
  80. preg_match('/\[(.*)]/', $this->rules[$key], $value);
  81. if ($this->checkLength($value[1]) === false)
  82. $errors[] = $this->rules[$key];
  83. }
  84.  
  85. if (in_array('valid_email', $this->rules))
  86. if ($this->checkEmail() === false)
  87. $errors[] = 'valid_email';
  88.  
  89. return (empty($errors)) ? true : $errors;
  90. }
  91.  
  92. /**
  93.   * Separation of validation rules
  94.   *
  95.   * @param $rules Field validation rules
  96.   */
  97. private function explodeRules($rules)
  98. {
  99. $this->rules = explode('|', $rules);
  100. }
  101.  
  102. /**
  103.   * Finds that there is a pattern in the rules,
  104.   * like in_array with using regular expressions
  105.   *
  106.   * @param $pattern Search pattern in the table
  107.   */
  108. private function pregArrayKey($pattern)
  109. {
  110. return key(preg_grep($pattern, $this->rules));
  111. }
  112.  
  113. /**
  114.   * Checks and returns whether the value is empty
  115.   *
  116.   * @return bool Returns whether the value is empty
  117.   */
  118. private function checkRequired()
  119. {
  120. return (!empty($this->name)) ? true : false;
  121. }
  122.  
  123. /**
  124.   * Checks and returns whether the value is numeric
  125.   *
  126.   * @return bool Returns whether the value is numeric
  127.   */
  128. private function checkNumeric()
  129. {
  130. return (is_numeric($this->name)) ? true : false;
  131. }
  132.  
  133. /**
  134.   * Checks and returns whether the specified phrases are the same
  135.   *
  136.   * @return bool Returns whether the specified phrases are the same
  137.   */
  138. private function checkMatches($confirm)
  139. {
  140. return ($this->name == $confirm) ? true : false;
  141. }
  142.  
  143. /**
  144.   * Checks and returns whether the value of a specified minimum length
  145.   *
  146.   * @return bool Returns whether the value of a specified minimum length
  147.   */
  148. private function checkMinLength($value)
  149. {
  150. return (strlen($this->name) > $value) ? true : false;
  151. }
  152.  
  153. /**
  154.   * Checks and returns whether the value of a specified maximum length
  155.   *
  156.   * @return bool Returns whether the value of a specified maximum length
  157.   */
  158. private function checkMaxLength($value)
  159. {
  160. return (strlen($this->name) < $value) ? true : false;
  161. }
  162.  
  163. /**
  164.   * Checks and returns whether the value of a specified length
  165.   *
  166.   * @return bool Returns whether the value of a specified length
  167.   */
  168. private function checkLength($value)
  169. {
  170. return (strlen($this->name) == $value) ? true : false;
  171. }
  172.  
  173. /**
  174.   * Checks and returns whether the given value is a valid email address
  175.   *
  176.   * @return bool Returns whether the given value is a valid email address
  177.   */
  178. private function checkEmail()
  179. {
  180. return (preg_match('/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/', $this->name)) ? true : false;
  181. }
  182.  
  183. }


Przykład użycia:
  1. <?php
  2. $formValidation = new ValidationData;
  3.  
  4. $age = '123';
  5. var_dump($formValidation->validate($age, "required|numeric|max_length[4]"));
  6.  
  7. $name = 'Kuba';
  8. var_dump($formValidation->validate($name, "required|min_length[5]"));
  9.  
  10. $pass = 'test';
  11. $pass_c = 'test';
  12. var_dump($formValidation->validate($pass, "required|matches[$pass_c]|exact_length[4]"));
  13.  
  14. $email = 'test1test.pl';
  15. if ($formValidation->validate($email, "required|valid_email") === true)
  16. echo 'Adres e-mail '.$email.' poprawnie zostal zwalidowany';
  17. else {
  18. echo 'Blad, adres e-mail '.$email.' nie zostal poprawnie zwalidowany, ponizej bledy w tablicy $errors:<br />';
  19. var_dump($formValidation->validate($email, "required|valid_email"));
  20. }
Crozin
Brak możliwości normalnej rozbudowy czy brak jakiejkolwiek informacji o wykrytych błędach kompletnie dyskwalifikuje tą klasę.
in5ane
O tym, żeby wskazywać, jaki błąd to myślałem, o to ją rozbuduję. A co do normalnej rozbudowy, co masz na myśli? Jakiś przykład i dlaczego mojej klasy nie można rozbudować?

@edit: dodałem wyświetlanie, jaki jest błąd.
Crozin
Cytat
@edit: dodałem wyświetlanie, jaki jest błąd.
Zwracane informacje są bardzo nieprecyzyjne. Zamiast konkretnego zestawu informacji np. "tekst za krótki, min. 6 znaków, podano: 2" (oczywiście w formie, którą da się normalnie przetwarzać) dostaję jedynie "tekst za krótki".
Cytat
A co do normalnej rozbudowy, co masz na myśli? Jakiś przykład i dlaczego mojej klasy nie można rozbudować?
Powiedzmy, że chcę wykorzystać Twoją klasę. Jak miałbym dodać do niej nowy walidator, np. sprawdzający poprawność nr NIP bez ingerencji w Twój kod? Nie da się tego zrobić normalnie.
gitbejbe
zgadzam się z przedmówcą.
Troche źle to wykombinowałeś bo teraz jeśli chciałbym dodać jakąś funkcje to muszę najpierw napisać jedną która wyłapie nazwe walidatorą, a póśniej drugą która jest uruchamiana z tej pierwszej tylko po to aby coś sprawdzić.. słaba opcja i sam zobaczysz, ze przy np 50 różnych walidatorach będziesz pisać 2 razy więcej kodu niż powinieneś i łatwo się pogubisz.

ostatnio wrzucałem tutaj swoja klasę walidacji
https://gist.github.com/gitbejbe/6762020

nie jest może ona super fajna i nie wiadomo co jeszcze, ale działa i dobrze mi się z nią pracuje : ) + taki, że łatwo można ją rozbudować o co się chce i jest mega prosta. Przydałoby sie jej jeszcze definiowanie niestandardowych treści błędu. Tak czy siak jakby co będziesz mieć porównanie : ) sam też pisałem patrząc na działanie innych
pyro
Obie te klasy są bez sensu. Słyszeliście w ogóle kiedyś o programowaniu obiektowym? Oboje jedyne co zrobiliście, to zapakowaliście zbiór funkcji w "class". Klasa @gitbejbe już trochę lepiej ze względu na engine, ale i tak spore pominięcie z sensem.
gitbejbe
obiektówką zajmuje sie od niedawna, a ta klasa to pierwsze co napisałem w oop. Lecę teraz na codeigniterze i nie daje sobie ręki uciąć bo tylko rzuciłem okiem na ich skrypt walidacji i wydaje mi się, że schemat jest podobny - po za tym, że zasady określa się w jednym stringu rodzielonym znakiem | oraz pomijając pozostałe funkcje pomocnicze. Walidatory uruchamia wtedy skrypt a nie ja osobiście odwołując się do danego walidatora (na początku własnie tego typu napisałem skrypt, ale później przerobiłem go na to bo ktoś tutaj napisał, ze tak będzie lepiej).Tej klasie dużo brakuje i jestem tego świadom ale działać działa i spełnia swoją role bez zarzutu i można ją łatwo rozszerzać, a wkleiłem ją tylko po to aby autor tematu mógł sobie ją porównać

Będę wdzięczny jeśli powiesz mi co jest głównie nie tak i jak powinien wyglądać prawdziwy schemat takiego skryptu. Z chęcią przyjmę każdą rade : )
phpion
Zobaczcie jak wygląda walidacja danych w Kohanie 3:
http://kohanaframework.org/3.3/guide/kohan...rity/validation
Moim zdaniem obok Query Buildera dla bazy danych jest to najmocjniejszy punkt Kohany. W Waszych kodach brakuje mi chociażby możliwości dodania callbacka (np. array($obj, 'validateMe')) - nie trzeba wówczas tworzyć globalnej metody walidacyjnej, która i tak nie byłaby użyta w obrębie innej walidacji.
Crozin
@gitbejbe: Na CodeIgnitera nawet nie patrz - to kompletna parodia OOP.
pyro
Cytat(gitbejbe @ 5.11.2013, 15:41:07 ) *
obiektówką zajmuje sie od niedawna, a ta klasa to pierwsze co napisałem w oop. Lecę teraz na codeigniterze i nie daje sobie ręki uciąć bo tylko rzuciłem okiem na ich skrypt walidacji i wydaje mi się, że schemat jest podobny - po za tym, że zasady określa się w jednym stringu rodzielonym znakiem | oraz pomijając pozostałe funkcje pomocnicze. Walidatory uruchamia wtedy skrypt a nie ja osobiście odwołując się do danego walidatora (na początku własnie tego typu napisałem skrypt, ale później przerobiłem go na to bo ktoś tutaj napisał, ze tak będzie lepiej).Tej klasie dużo brakuje i jestem tego świadom ale działać działa i spełnia swoją role bez zarzutu i można ją łatwo rozszerzać, a wkleiłem ją tylko po to aby autor tematu mógł sobie ją porównać

Będę wdzięczny jeśli powiesz mi co jest głównie nie tak i jak powinien wyglądać prawdziwy schemat takiego skryptu. Z chęcią przyjmę każdą rade : )


OOP to zabawa w klocki. Muszą być one łatwo nakładane, zdejmowane, wymieniane. Klasy powinny być tworzone tak, aby nie trzeba było ingerować w ich kod dodając kolejne funkcjonalności, tylko bawić się klockami.

Zarówno w Twojej jak i @insane'a klasach nie ma możliwości manipulowania walidatorami. Są one wstawione na sztywno i koniec... nic nie zmienisz bez ingerencji w istniejący już kod. Jedyną możliwością byłoby rozszerzanie klasy za każdym razem jak chcesz dodać kolejny walidator. Ale jak wtedy będziesz nazywał dzieci klasy?

- Validator -> ValidatorWithNip -> ValidatorWithNipAndIdentityCardNumber -> validatorWithNipAndIdentityCardNumberAndImageSize... itd? Zupełnie bez sensu. Poza tym jak będziesz chciał z tego schematu tylko kolejne walidatory Nip i ImageSize bez IdentityCardNumber, to co zrobisz? Nic.

Przykładowa implementacja mająca sens:

Powinien zostać stworzony jakiś menadżer walidatora:

  1. class Validator {
  2.  
  3. private $fields;
  4. // inne pola...
  5.  
  6. public function addField($name) {
  7. // ...dodawanie pól
  8. }
  9.  
  10. public function removeField($name) {
  11. // ... usuwanie
  12. }
  13.  
  14. public function setFields(array $fields) {
  15. // ...
  16. }
  17.  
  18. public function addConstraint($field, ConstraintInterface $constraint) {
  19. // Dodawanie przymusu implementującego interfejs ConstraintInterface dla jakiegoś pola
  20. }
  21.  
  22. public function removeConstraint() {
  23. // Zdejmowanie przymusu
  24. }
  25.  
  26. public function setConstraints($field, array $constraints) {
  27. // tu należy pamiętać żeby sprawdzać czy każdy constraint implementuje ConstraintInterface (innymi słowy używasz $this->setConstraint, który robi to za Ciebie)
  28. }
  29.  
  30. public function setValue($field, $value) {
  31. // przypisywanie wartości polu
  32. }
  33.  
  34. public function setValues(array $values) {
  35. // ... lub polom z tablicy
  36. }
  37.  
  38. public function validate() {
  39. // ...
  40. }
  41.  
  42. // ... inne metody, np. setter dla wiadomości dla wyjątków i takie tam
  43.  
  44. }


Teraz należy stworzyć interfejs dla przymusów:

  1. interface ConstraintInterface {
  2.  
  3. public function __construct();
  4. public function setValue($value);
  5. public function getValue();
  6. public function validate();
  7. // inne wedle życzenia...
  8.  
  9. }


Możemy teraz tworzyć dowolne przymusy implementując stworzony interfejs:

  1. class Nip implements ConstraintInterface {
  2. // ...
  3. }
  4.  
  5. class Length implements ConstraintInterface {
  6. // ...
  7. }
  8.  
  9. // ... itd


I teraz możemy dowolnie manipulować przymusami dla dowolnych pól:

  1. $validator = new Validator();
  2.  
  3. $validator->setFields(array(
  4. 'name',
  5. 'nip',
  6. 'email'
  7. ));
  8.  
  9. $validator->setConstraints('name', array(
  10. new NotEmpty(array(
  11. 'message' => 'Imię nie może być puste'
  12. )),
  13. new Length(array(
  14. 'min' => 3,
  15. 'max' => 10,
  16. 'minMessage' => 'Imię musi mieć minimum {{ min }} znaków',
  17. 'maxMessage' => 'Imię musi mieć maximum {{ max }} znaków'
  18. ))
  19. ));
  20.  
  21. $validator->setConstraints('nip', array(
  22. new NotEmpty(array(
  23. 'message' => 'Nip nie może być pusty'
  24. )),
  25. new Nip(array(
  26. 'message' => 'Nieprawidłowy NIP'
  27. ))
  28. ));
  29.  
  30. $validator->setConstraints('email', array(
  31. new NotEmpty(array(
  32. 'message' => 'E-mail nie może być pusty'
  33. )),
  34. new Email(array(
  35. 'checkMX' => true,
  36. 'message' => 'Nieprawidłowy adres e-mail'
  37. ))
  38. ));


Wszystko pisane z palca, więc mogą być literówki, ale chodzi o zasadę działania. Budowa klockowa wink.gif
gitbejbe
pyro

welkie dzięki za to, że chciało Ci się opisać to w ten sposób : ) Na pewno to przeanalizuje i przerobie swój skrypt walidacji : ) Podeśle go na forum jak skończe. Trudno jest dojść do czegoś/wpaść na coś samemu nie mając osoby od której można się uczyć, dlatego warto tutaj zaglądać : )
pionas
Szukam podobnego rozwiązania, tzn. takiego gdzie podaję dane i tworzony jest formularz i po kliknięciu w submit dopiero sprawdza walidację.
Macie może coś takiego? Znalazłem "PHP Form Builder Class", jest rozbudowany, ale nie ma możliwości ustalenia min i max lenght, fajna za to jest opcja przechowywania danych w formularzu nawet po powrocie z innej podstrony (dane przechowywane są w sesji).
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.