MVC и валидация

MiksIr

miksir@home:~$
в этом и есть предназначение контроллера - управлять (контроллировать) потоки
Если честно, для меня загадка, откуда это пошло. Ведь даже в классическом десктопном MVC контроллер - это средства изменения состояния модели, а представление отображает состояние модели.
 

stwa

Новичок
Смотря что понимать под "средством изменения состояния модели"
Если это часть бизнес-логики, то это уже будет ТТУК — «Толстые тупые уродливые контроллеры»
http://ru.wikipedia.org/wiki/Model-View-Controller#.D0.9D.D0.B0.D0.B8.D0.B1.D0.BE.D0.BB.D0.B5.D0.B5_.D1.87.D0.B0.D1.81.D1.82.D1.8B.D0.B5_.D0.BE.D1.88.D0.B8.D0.B1.D0.BA.D0.B8
Что не есть хорошо, как утверждают гуру
Та же википедия дает нам определение контроллера в модели MVC (цитата):
"...выполняет исключительно функцию связующего звена (glue layer) между отдельными компонентами системы"
 

fixxxer

К.О.
Партнер клуба
Ё, а когда я ровно то же самое говорил сто лет назад, меня никто не слушал :/
 

vanicon

Новичок
Вот неплохо выражено словами то, что я думаю =))
Прочитал, и местами не понял на счет отказа от контроллера при запросах на чтение...
Вот к примеру всем известная ситуация, страничка профиля пользователя.
Что происходит при запросе на эту страницу в обычном фреймворке:
1. Роутер разбирает запрос, ищет нужный контроллер и действие.
Если все ок, то вызываем действие контроллера, если что-то не то то вызываем контроллер error допустим с методом 404.
2. Контроллер проверяет может ли пользователь выполнить это действие (авторизирован ли он, не забанен ли по ip или еще чего), и если все норм, то берем нужные данные (можно целиком объект) и передаем их в представление...
Так собственно вопрос, как в этом случае избавиться от контроллера (названного посредника из статьи), ведь он также проверяет доступность данного действия, а роутер вызвать что должен сразу представление? А куда же тогда логику проверку авторизации и ее подобную?
Объясните пожалуйста, если я что-то не понял...
 

WMix

герр M:)ller
Партнер клуба
stwa
Где тут зависимость модели от представления?
я понимаю, ты переписываешь модель на уровне controller для view,! классно, молодец, я понял тебя, нет прямой зависимости, но я люблю крутить сущьностью как коллекцией, желая чтоб одно слово говорило о 10ке слов, по этой причине я думаю что view зависит (общается, получает данные, ассоциирует) с model
 

stwa

Новичок
vanicon
Проверка прав доступа должна делаться еще до контроллера в момент диспетчеризации и если у юзера нет прав на выполнение какого-то действия, то до контроллера он не дойдет, а получит 403-ю.
Если у тебя не одна, а сотня страниц, к которым доступ должен иметь, например, только админ, да все еще это разбросано по 10-ку контроллеров, то ты ведь не будешь в каждом контроллере дублировать код проверки авторизован юзер или нет, какая у юзера роль (админ или нет) и т.д.

WMix
Это не моя цитата. Я наоборот согласен, что представление должно иметь тесную связь с моделью. Кроме того стал понимать, что когда контроллер выступает только в роли посредника между моделью и представлением (взять модель и бросить ее в представление), то это тоже не очень хорошо. Представление должно само дергать модель для получения данных с помощью хэлперов.

MiksIr
Согласно переводу на хабре, самый лучший контроллер - пустой контроллер. Это отчасти верно, когда не надо разбирать ввод от пользователя
 

vanicon

Новичок
Если у тебя не одна, а сотня страниц, к которым доступ должен иметь, например, только админ, да все еще это разбросано по 10-ку контроллеров, то ты ведь не будешь в каждом контроллере дублировать код проверки авторизован юзер или нет, какая у юзера роль (админ или нет) и т.д.
Но обычно я делаю 2 базовых котроллера, в 1 прописываю что права нужны админа, в другом что простой пользователь тоже сойдет, и наследую их если нужно...
Согласно переводу на хабре, самый лучший контроллер - пустой контроллер. Это отчасти верно, когда не надо разбирать ввод от пользователя
Прошу привести пример, где можно отказаться от контроллера.
 

WMix

герр M:)ller
Партнер клуба
stwa
Это не моя цитата.
извеняюсь :),
Представление должно само дергать модель для получения данных с помощью хэлперов.
а что такое хелпер? Представление должно имеет уже не модель а rowset (в моем случае это чаще масив) и хотя это тоже модель но это уже результат обработки.
 

Василий М.

Новичок
У меня вся валидация моделей зашита в самих моделях. Обратите внимание на массивы валидаторов, они описывают форматы, которые допустимы:

PHP:
<?php
class Krugozor_Module_User_Model_User extends Krugozor_Model
{
    /**
     * Время жизни cookie гостя - 10 лет.
     *
     * @var int
     */
    protected static $unique_user_cookie_id_lifetime = 315360000;

    /**
     * Имя cookie гостя
     *
     * @var string
     */
    public static $unique_user_cookie_id_name = 'unique_user_cookie_id';

    protected static $db_field_prefix = 'user';

    protected static $model_attributes = array
    (
        'id' => array('db_element' => false,
                      'default_value' => 0,
                      'validators' => array(
                          'Common/Decimal' => array('signed' => true),
                      )
                     ),

        'unique_cookie_id' => array('db_element' => true,
                                    'db_field_name' => 'user_unique_cookie_id',
                                    'validators' => array(
                                        'Common/StringLength' => array(
                                            'start' => 0,
                                            'stop' => Krugozor_Module_Common_Validator_StringLength::MD5_MAX_LENGTH),
                                        'Common/CharPassword' => array(),
                                    )
                                   ),

        'active' => array('db_element' => true,
                          'db_field_name' => 'user_active',
                          'default_value' => 1,
	                      'validators' => array(
                              'Common/EmptyNull' => array(),
	                          'Common/Decimal' => array('signed' => false),
                              'Common/IntRange' => array('min' => 0, 'max' => 1),
	                      )
	                     ),

        'group'  => array('db_element' => true,
                          'db_field_name' => 'user_group',
                          'default_value'=> 2, // 2 - ID группы Пользователи
	                      'validators' => array(
	                          'Common/Empty' => array(),
                              'Common/Decimal' => array('signed' => false),
                          )
                         ),

        'login'  => array('db_element' => true,
                          'db_field_name' => 'user_login',
                          'validators' => array(
                              'Common/EmptyNull' => array(),
                              'Common/StringLength' => array(
                                  'start' => 0,
                                  'stop' => Krugozor_Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH),
                              'Common/CharPassword' => array(),
                          )
                         ),

        'email'   => array('type' => 'Krugozor_Module_Common_Type_Email',
                          'db_element' => true,
                          'default_value' => null,
                          'db_field_name' => 'user_email',
                          'validators' => array(
                              'Common/StringLength' => array(
                                  'start' => 0,
                                  'stop' => Krugozor_Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH),
                              'Common/Email' => array(),
                          )
                         ),

        'password' => array('db_element' => true,
                            'db_field_name' => 'user_password',
	                        'validators' => array(
	                            'Common/CharPassword' => array(),
	                        )
	                       ),

        'regdate'  => array('type' => 'Krugozor_Module_Common_Type_Datetime',
                            'db_element' => true,
                            'db_field_name' => 'user_regdate',
                            'default_value' => 'now',
	                        'validators' => array(

                            )
                           ),

        'visitdate' => array('type' => 'Krugozor_Module_Common_Type_Datetime',
                             'db_element' => true,
                             'db_field_name' => 'user_visitdate',
                             'default_value' => null,
                             'validators' => array(

                             )
                            ),

        'ip'     => array('db_element' => true,
                          'db_field_name' => 'user_ip',
                          'default_value' => null,
                          'validators' => array(
                              //'Common/FixedStringLength' => array(15),
                          )
                         ),

        'first_name' => array('db_element' => true,
                              'db_field_name' => 'user_first_name',
                              'default_value' => null,
	                          'validators' => array(
	                              'Common/StringLength' => array('start' => 0, 'stop' => 30),
	                          )
	                         ),

        'last_name' => array('db_element' => true,
                             'db_field_name' => 'user_last_name',
                             'default_value' => null,
                             'validators' => array(
                                 'Common/StringLength' => array('start' => 0, 'stop' => 30),
                             )
                            ),

        'age' => array('type' => 'Krugozor_Module_Common_Type_Datetime',
                       'db_element' => true,
                       'db_field_name' => 'user_age',
                       'default_value' => null,
                       'validators' => array(

                       )
                      ),

        'sex' => array('type' => 'Krugozor_Module_User_Type_Sex',
                       'db_element' => true,
                       'db_field_name' => 'user_sex',
                       'default_value' => null,
                       'validators' => array(
                           'Common/StringLength' => array('start' => 1, 'stop' => 1),
                           'Common/VarEnum' => array('enum' => array('M', 'F')),
                       )
                      ),

        'city' => array('db_element' => true,
                        'db_field_name' => 'user_city',
                        'default_value' => 0,
                        'validators' => array(
                            'Common/Decimal' => array('signed' => false),
                        )
                       ),

        'region' => array('db_element' => true,
                          'db_field_name' => 'user_region',
                          'default_value' => 0,
                          'validators' => array(
                              'Common/Decimal' => array('signed' => false),
                          )
                         ),

        'country' => array('db_element' => true,
                           'db_field_name' => 'user_country',
                           'default_value' => 0,
                           'validators' => array(
                               'Common/Decimal' => array('signed' => false),
                           )
                          ),

        'phone' => array('db_element' => true,
                         'db_field_name' => 'user_phone',
                         'default_value' => null,
                         'validators' => array(
                             'Common/StringLength' => array(
                                 'start'=> 0,
                                 'stop' => Krugozor_Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH),
                         )
                        ),

        'icq' => array('db_element' => true,
                       'db_field_name' => 'user_icq',
                       'default_value' => null,
                       'validators' => array(
                           'Common/Decimal' => array('signed' => true),
                           'Common/IntRange' => array(
                               'min' => 10000,
                               'max' => Krugozor_Module_Common_Validator_IntRange::PHP_MAX_INT_32)
                       )
                      ),

        'url' => array('db_element' => true,
                       'db_field_name' => 'user_url',
                       'default_value' => null,
                       'validators' => array(
                           'Common/StringLength' => array(
                               'start' => 0,
                               'stop' => Krugozor_Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH),
                           'Common/Url' => array()
                       )
                      ),
    );
 

vanicon

Новичок
У меня вся валидация моделей зашита в самих моделях. Обратите внимание на массивы валидаторов, они описывают форматы, которые допустимы:
Видел что-то похожее в cake, то есть у вас в модели зашита проверка и на капчу и на повтор пароля, а как же тогда вы проверяете поступающие данные, типа здесь должна на странице регистрации проверяться капча, а вот на этой странице не должна...
 

Василий М.

Новичок
1. модель не может иметь 2 разных состояний. тут могу, тут не могу.
2. капча к моделям не имеет никакого отношения.
ровно как и ввод 2 раз пароля.
это все делается отдельно, у меня - в контроллерах (если логика усложняется - пишу отдельные объекты-сервисы для этого):
PHP:
// капча 
$validator->add('captcha', new Krugozor_Module_Common_Validator_Captcha(
            $this->getRequest()->getPost('captcha_code'), Krugozor_Session::getInstance()->code
        ));

// ввод праоля 2 раза
        if (!empty($this->getRequest()->getRequest()->user->password_1) &&
            !empty($this->getRequest()->getRequest()->user->password_2))
        {
            $validator->add('password',
                            new Krugozor_Module_User_Validator_UserPasswordsCompare(
                                $this->getRequest()->getRequest()->user->password_1,
                                $this->getRequest()->getRequest()->user->password_2
                                )
                           );
        }
 

vanicon

Новичок
1. модель не может иметь 2 разных состояний. тут могу, тут не могу.
2. капча к моделям не имеет никакого отношения.
ровно как и ввод 2 раз пароля.
это все делается отдельно, у меня - в контроллерах (если логика усложняется - пишу отдельные объекты-сервисы для этого):
Я ровном счетом согласен с вами, но вроде бы в контроллере так делать не хорошо...
Выше предложили вынести валидацию в отдельный класс, и там уже он может все валидировать, вот
 

fixxxer

К.О.
Партнер клуба
и раздел "Наиболее частые ошибки" тоже мой
Про активных и пассивных сам придумал? =) Строго говоря, нет никаких активных и пассивных, есть MVC и не MVC. :) "Не-MVC" само по себе нарушает кучу принципов объектного дизайна.
 
Сверху