За последние 24 часа нас посетили 22205 программистов и 1060 роботов. Сейчас ищут 628 программистов ...

Хочу обсудить некоторые аспекты генерации/обработки форм

Тема в разделе "Решения, алгоритмы", создана пользователем akrinel, 30 янв 2009.

  1. akrinel

    akrinel Активный пользователь

    С нами с:
    26 янв 2009
    Сообщения:
    955
    Симпатии:
    1
    Адрес:
    Spb
    Уважемые посетители форума.
    Хотелось бы проконсультироваться с Вами по нескольким вопросам создания форм.

    Таким как:
    0) Проверка данных.
    1) Обработка данных(отправка, сохранение/изменение существующих данных и т.д.).
    2) Возврат ошибок в случае неудачи.

    Дело в том что, с самого начала изучения PHP, обработка данных от пользователей была для меня проблемным местом.
    Почему-то мне никак не удается логично и аккуратно сделать обработку данных форм и вывод ошибок.
    Эти вещи почему-то превращаются в отвратительный фарш "все в одном файле лишь бы работало".

    Пример такого фарша*:

    PHP:
    1.  
    2. <?php
    3.     try{
    4.         $user  =  tUsers::getParam($uid);
    5.     }
    6.     catch(Exception $e){
    7.         headers('Location: /'.tConfig::getParam('adminLink').'/users/list/');
    8.     }
    9.  
    10.     $data  =  array();
    11.  
    12.     if(!empty($_POST)){
    13.         //Если полей много присваиваем значения в цикле
    14.         $data['login']  =  (isset($_POST['login']))  ?  $_POST['login']  :  null;
    15.         $data['email']  =  (isset($_POST['email']))  ?  $_POST['email']  :  null;
    16.         $errors  =  false;
    17.         $errorHtml  =  array();
    18.        
    19.         //  -|| - ||-- || - ||- -|| - ||-
    20.         $errorHtml['login']  =  $errorHtml['email']  =  null;
    21.        
    22.         //  -|| - ||-- || - ||- -|| - ||-
    23.         if(empty($data['login'])){
    24.             $errorHtml['login']  =  'Поле &laquo;логин&raquo; обязательно для заполнения.';
    25.             $errors  =  true;
    26.         }
    27.        
    28.         if(empty($data['email'])){
    29.             $errors  =  true;
    30.             $errorHtml['email']  =  'Поле &laquo;E-mail&raquo; обязательно для заполнения.';
    31.         }
    32.         elseif(!preg_match('^[a-z0-9\._-]+@[a-z0-9\._-]+\.[a-z]{2,4}\$', $data['email'])){
    33.             $errors  =  true;
    34.             $errorHtml['email']  =  'Неверный E-mail';
    35.         }
    36.     }
    37.     else{
    38.         $data['login']  =  $user->getParam('login');
    39.         $data['email']  =  $user->getParam('email');
    40.     }
    41.    
    42.    
    43.     if(empty($_POST) || $errors){
    44.        
    45.         if(!empty($errorHTML)){
    46.             foreach($errorHtml  as  $key=>$value){
    47.                 $errorHtml[$key]  =  '<li class="error">'.$value.'</li>';
    48.             }
    49.         }
    50.  
    51.         //  -|| - ||-- || - ||- -|| - ||-
    52.         return  '
    53.             <ul>
    54.                 <li>Логин</li>
    55.                 <li><input type="text" name="login" value="'.$data['login'].'" /></li>
    56.                 '.$errorHtml['login'].'
    57.                 <li>E-mail</li>
    58.                 <li><input type="text" name="email" value="'.$data['email'].'" /></li>
    59.                 '.$errorHtml['email'].'
    60.                 <li><button type="submit">Сохранить изменения</button></li>
    61.             </ul>
    62.         ';
    63.     }
    64.     else{
    65.  
    66.         $user->setParam('login', $login);
    67.         $user->setParam('email', $email);
    68.         $user->save();
    69.  
    70.         return  'Изменения сохранены.';
    71.     }
    72. ?>
    73.  
    Как Вы понимаете, при наличии полей 10, среди которых найдется пара селектов, несколько чекбоксов и т.д. и т.п. код становиться:
    0) Трудно читаемым - с первого взгляда непонятно где у нас собственно действие происходит, где такая-то обработка и т.д. и т.п.
    1) Трудно расширяемым - добавление еще одного поля, изменение какой-нибудь проверки легко может вызвать коллапс :).
    2) Легко забываемым - через месяц приходится потратить много времени что бы вспомнить, что делает эта вот проверка и зачем.

    Через 1.5 года(быстро до меня доходит :) мне это надоело.
    Я начал думать над решением "проблемы F".
    Наверное гугл у меня плохо работает поэтому ничего, что бы меня устроило я не нашел.

    В теории я предполагал что-то такое:


    Все данные по форме вынесены в отдельный файл. /data/forms/form-name.php

    Этот файл возвращает ассоциативный массив который может содержать:

    0) 'inputDataType' - где искать данные формы (post/get/partUrl).

    1) 'handler' - какому обработчику передавать данные формы после проверки (tMail::sendFromAdmin).

    2) 'outputDataType' - что возвращаем (html/xml/JSON).

    3) Список полей для которых мы указываем:

    а) 'type' - тип (text/hidden/password/...)

    б) 'loadFrom' - откуда брать начальное значение ($user->getParam('login')).

    в) 'check' - список проверок(см. ниже).

    г) 'errorMsg' - тексты для различных ошибок. ('не введен пароль' || tMultilang::getMsg('empty_password', 'system'));

    список проверок - таких как:
    0) 'requied' - поле обязательно для заполнения
    1) 'max-size' - максимальное значение
    2) 'min-size' - минимальное значение
    3) 'abc' - только буквы
    4) 'digit' - только цифры
    5) 'not' - все кроме знаков здесь перечисленных ('"/^&)
    6) 'rus' - при проверке букв русские тоже канают
    7) 'url' - похож на адрес
    8) 'mail' - похож на мыло
    ...........................
    N) 'result' - если из (tUsers::userNotExist) вернулось true то все хорош
    N+1) 'result-1' - аналогично N)

    Ну и предполагается наличие 2-х классов:

    tForms.
    0) Смотрит что за форма/формы Назначены на данную страницу.
    1) Подгружает их или выдает formsGenException extends Exception.
    2) По запросу tForms::drow('formName'); вызовет self::forms['formName']->drow();

    tForm
    0) Генрит html для формы (с сообщениями об ошибках или же без таковых).
    1) Проверяет на ошибки.
    2) В случае, если все хорошо вызывает метод указанный в handler.


    Но мне кажется что подобная вещь:
    0) Будет тормозить.
    1) Как-то монстрообразна, слишком много нужно иметь форм на проекте что бы ее "окупить".
    2) Очень смахивает на велосипед с 4-мя колесами, 2-мя рамами и одним седлом.

    Вопросы к коллегам по цеху:
    0) Как обрабатываете формы Вы?
    1) Как думаете подобная вещь будет очень сильно тормозить?
    2) Быть может генерацию html-a для форм спихнуть на клиента?
    3) Я придумал себе проблему и теперь мучаюсь пытаясь ее решить?
    4) К стыду своем очень мало разбирался с Симфони, Зенд фреймворк и кэйк не ставил вовсе. Вы с ними работаете? Как это реализовано там?
    5) Как Вы думаете, как будут выглядеть для такого чуда шаблоны(шаблоны это тоже у меня больной вопрос :)?
    6) Если сама идея кажется Вам не бредовый, что бы Вы предложили добавить к этой штуке?

    * - Здесь и далее код, никакой смысловой нагрузки не несет, набран для наглядности, на работоспособность не тестировался.

    P.S. жена таки вытащила меня из-за компьютера :( , позже буду онлайн и обязательно всем на все отвечу.
     
  2. http://dklab.ru/lib/HTML_FormPersister/
    http://pear.php.net/manual/en/package.h ... amples.php
    Нормально. Форма сама себя валидирует.
     
  3. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Например, так:

    PHP:
    1. <?php print $form->begin()?>
    2.     <p>
    3.         Логин: <?php print $form->login?><br />
    4.         Пароль: <?php print $form->password?>
    5.     </p>
    6.     <p>
    7.         <?php print $form->submit?>
    8.     </p>
    9. <?php print $form->end()?>
     
  4. akrinel

    akrinel Активный пользователь

    С нами с:
    26 янв 2009
    Сообщения:
    955
    Симпатии:
    1
    Адрес:
    Spb
    флоппик, спасибо за ссылки, обязательно ознакомлюсь.
    По поводу фреймворков - в них всех форма сама себя валидирует или только в "избранных"?
    Нормально => стоит посмотреть как реализованно?

    Sergey89, у меня похожим образом реализованы собственно шаблоны страниц:
    PHP:
    1.  
    2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    3. <html>
    4.   <head>
    5.       <title><?php  echo  tPages::getTitle();  ?></title>
    6.     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    7.         <meta content="<?php  echo  tPages::getMeta();  ?>" name="keywords" />
    8.     <script type="text/javascript" src="/js/jquery.js"></script>
    9.     <?php  echo  tPages::getJs(); ?>
    10.     <?php  echo  tPages::getCss(); ?>
    11.   </head>
    12.   <body>
    13.     <div id="body">
    14.         <div id="header">
    15.             <div id="login">
    16.                 <p id="login-message">
    17.                     <?php echo  tPages::getContent('login'); ?>
    18.                     <br />
    19. ...........................................
    20.  
    Но я когда заходил на страницу Smarty краем глаза видел, что там еще куча каких-то бонусов, типа какие-то шаблонные циклы ифы и прочее.
    Не пробовал так делать оно вообще нужно? :)
     
  5. В симфонии. В остальных не знаю. Мне вообще в этом плане нравятся newforms в django... все хочу аналог в php реализовать.
     
  6. А ты так быстро? Жена отпустила? ))
     
  7. akrinel

    akrinel Активный пользователь

    С нами с:
    26 янв 2009
    Сообщения:
    955
    Симпатии:
    1
    Адрес:
    Spb
    Очень торопился почитать ответы))

    О еще и django. Обязательно погуглю.
     
  8. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Использую try {} catch () {}, форма валидирует сама себя. Ошибка - Exception. Мне нравиться, код стройный. Конечно приходится по старинке все проверки писать, но от пары if (empty($_POST['field'])) { throw new Exception(_("Message")); } не помру :)