Расширение rules() моделей

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
Alex Bel
Сообщения: 12
Зарегистрирован: 2012.01.11, 22:12

Расширение rules() моделей

Сообщение Alex Bel »

Покажу на примере профиля пользователя. Итак мы имеем

AccountController::actionRegistration() // регистрация пользователя;
в качестве модели используется RegistrationForm унаследованный от User, переопределён метод rules()

ProfileController::actionUpdate() // редактируем такие поля как имя пользователя (не логин), конт. инфа и т.д.
ProfileController::actionChangePassword // пользователь меняет пароль
и т.д.

Что бы реализовать два последних метода я нашёл два решения:
  • Первый. К этому я склоняюсь. Также как и для actionRegistration() создавать отдельные модели унаследованные от User, единственное что нам требуется это переопределить метод rules()
  • Второй. Этот вариант мне не очень нравится, но больше решений я не нашёл. Код см. ниже

Код: Выделить всё

class User extends CActiveRecord
{
    const MODE_A = a;
    const MODE_B = b;

    public $mode;

    public function rules()
    {
        switch($this->mode) {
            case 'a' :
                // возвращаем массив правил
            case 'b' :
                // возвращаем другой массив правил
    }
}
 
Св-во $mode устанавливаем из контроллёра. А дальше из свича возвращаем нужный набор правил.

Если кто-то знает более красивое, опциональное решение напишите пожалуйста.

Что касается меня, использую оба варианта. Первый, если я не уверен на сколько класс будет расширяться. Второй, если модель "узкой специализации" и я уверен, что в дальнейшем мне не придётся его использовать вне контроллёра или модуля.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Расширение rules() моделей

Сообщение andy_s »

$mode - это случайно не то же самое, что и сценарий валидации? Соответствующий раздел гайда: http://www.yiiframework.com/doc/guide/1.1/ru/form.model
Alex Bel
Сообщения: 12
Зарегистрирован: 2012.01.11, 22:12

Re: Расширение rules() моделей

Сообщение Alex Bel »

andy_s писал(а):$mode - это случайно не то же самое, что и сценарий валидации? Соответствующий раздел гайда: http://www.yiiframework.com/doc/guide/1.1/ru/form.model
Абсолютно верно. Я изобретатель велика :? . Но хотелось бы увидеть ещё варианты реализаций, в рамках идеологии Yii.
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Расширение rules() моделей

Сообщение TM123 »

Я использую примерно такой же способ, только в rules анализируется набор некоторых параметров и возвращаются соответствующие правила.

В принципе все устраивает, но тоже хотел бы узнать более красивый метод, например, может можно задавать свой rules для режимов работы модели.
Alex Bel
Сообщения: 12
Зарегистрирован: 2012.01.11, 22:12

Re: Расширение rules() моделей

Сообщение Alex Bel »

Мощная штука сценарии. В нескольких тестовых проектах переписал модели с применением сценариев, только наилучшие впечатления. По принципу очень схож с выше описанными режимами, но радует что есть в коробке.

Появился вопросик: Существуют ли методы, наподобие CController::action... или CController::filter..., кароче пользовательские методы которые вызываются для конкретного сценария? Понимаю, что для этого нужно учитывать в какой момент они должны быть вызваны, и скорее всего их нет, но попытка не пытка :). По существу реализовать самому не сложно.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Расширение rules() моделей

Сообщение andy_s »

Alex Bel писал(а):Появился вопросик: Существуют ли методы, наподобие CController::action... или CController::filter..., кароче пользовательские методы которые вызываются для конкретного сценария? Понимаю, что для этого нужно учитывать в какой момент они должны быть вызваны, и скорее всего их нет, но попытка не пытка :). По существу реализовать самому не сложно.
А в чём, собственно, задача? Сценарии относятся только к моделям и не должны быть связаны с чем-то, кроме моделей.
Alex Bel
Сообщения: 12
Зарегистрирован: 2012.01.11, 22:12

Re: Расширение rules() моделей

Сообщение Alex Bel »

наподобие CController::action... или CController::filter...
- я привёл эти методы в качестве примера функциональности.
Снимаю этот вопрос!
В случае необходимости можно будет сделать как метод класса ActiveRecord, либо бехавиором.
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Расширение rules() моделей

Сообщение TM123 »

Я имел в виду именно сценарии, т.е. хорошо бы если можно было бы иницировать модель со сценарием, например, insert2 и в этом случае вызывались бы соответственно rulesInsert2, а простой rules вызывался бы для все сценариев для которых не определен rulesScenarioname.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Расширение rules() моделей

Сообщение andy_s »

TM123 писал(а):Я имел в виду именно сценарии, т.е. хорошо бы если можно было бы иницировать модель со сценарием, например, insert2 и в этом случае вызывались бы соответственно rulesInsert2, а простой rules вызывался бы для все сценариев для которых не определен rulesScenarioname.
Всё это можно сделать внутри rules():

Код: Выделить всё

if ($this->scenario == 'insert2')
    ...
else
    ...
 
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Расширение rules() моделей

Сообщение TM123 »

Это костыльное решение не отличающееся от обсуждаемых вариантов, надо самому анализировать сценарий, это тоже самое что switch перебирать входной параметр как делает это автор темы или как я анализирую набор параметров доступных модели и выдаю нужные правила.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Расширение rules() моделей

Сообщение andy_s »

Если у вас так принципиально различаются сценарии моделей, то почему не сделать базовый класс и от него наследовать другие? В общем, без конкретного примера нет смысла обсуждать.
esche
Сообщения: 1054
Зарегистрирован: 2010.11.24, 03:39

Re: Расширение rules() моделей

Сообщение esche »

TM123 писал(а):Я имел в виду именно сценарии, т.е. хорошо бы если можно было бы иницировать модель со сценарием, например, insert2 и в этом случае вызывались бы соответственно rulesInsert2, а простой rules вызывался бы для все сценариев для которых не определен rulesScenarioname.
А чем не устраивает 'on'=>'scenarioName' ?
...
Alex Bel
Сообщения: 12
Зарегистрирован: 2012.01.11, 22:12

Re: Расширение rules() моделей

Сообщение Alex Bel »

Если у вас так принципиально различаются сценарии моделей, то почему не сделать базовый класс и от него наследовать другие? В общем, без конкретного примера нет смысла обсуждать.
Нет желания плодить значения правил. Например, длина поля 'username' - min=>6, теперь оно меняется, соответственно придётся менять во всех дочерних классах.

Вопрос
Если правила:

Код: Выделить всё

public function rules()
{
    return array(
        array('name, surname', 'required', 'on'=>'profile'),
        array('password', 'required', 'on'=>'changePassword'),

        array('password', 'length', 'min'=>6, 'max'=>32), // замечу, что, специально не установил сценарий
        array('password', 'compare', 'compareAttribute'=>'password2'),
    );
}
Теперь представим, кто то лезет в firebug и дописывает поле пароля. Получается, при вызове сценария profile так же будет изменён и пароль.
Каким образом можно спрятать поле password от сценария profile, не указывая у каждого правила сценарии? в идеале хочется сгруппировать поля которые относятся к определённому сценарию, наподобие как первые 2 строчки возвращаемого массива.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Расширение rules() моделей

Сообщение andy_s »

Как насчёт array('password', 'unsafe', 'on'=>'profile') ?
Alex Bel
Сообщения: 12
Зарегистрирован: 2012.01.11, 22:12

Re: Расширение rules() моделей

Сообщение Alex Bel »

unsafe не подойдёт, так как валидатор всё же пытается проверить пароль, в примере выше он будет проверять сопоставление с password2. Вот если бы как нибудь "отключить" не используемые поля.
Так же не стоит забывать, что длина пароля, предположим, 20 символов, а в действительности он хранится в хешированном виде, так что всплывает ещё одна проблема.

Конечно можно у подобных полей явно задать сценарии, но всё же хочется иметь набор неиспользуемых полей в одном месте, так и нагляднее и шанс допустить ошибки уменьшается.
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Расширение rules() моделей

Сообщение TM123 »

А чем не устраивает 'on'=>'scenarioName' ?
Наверное всем устраивает, просто забыл про такую возможность. Надо будут попробовать переписать на такую технологию.
netti
Сообщения: 2
Зарегистрирован: 2012.03.13, 22:24

Re: Расширение rules() моделей

Сообщение netti »

Помогите со следующей проблемкой/непониманием, пожалуйста
AccountController::actionRegistration() // регистрация пользователя;
в качестве модели используется RegistrationForm унаследованный от User, переопределён метод rules()

ProfileController::actionUpdate() // редактируем такие поля как имя пользователя (не логин), конт. инфа и т.д.
ProfileController::actionChangePassword // пользователь меняет пароль

Что бы реализовать два последних метода я нашёл два решения:
Первый. К этому я склоняюсь. Также как и для actionRegistration() создавать отдельные модели унаследованные от User, единственное что нам требуется это переопределить метод rules()
В этом решении всё вроде бы точно также, как и в случае регистрации - единственное отличие состоит в том, что пользователю должна быть показана уже заполненная форма - тут у меня и начинаются проблемы
И так:
Для достижения вот этого первого решения мы создаём модель UpdateForm

Код: Выделить всё

class UpdateForm extends User
{
    public function rules()
    {
        return array(
            array('email', 'required'),
            array('firstname, lastname', 'length', 'max'=>32),
            array('email', 'length', 'max'=>128),
            array('email', 'email'),
            /*...*/
        );
    }
}

 
Затем (если я правильно всё понял) в ProfileController::actionUpdate() мы вызываем $model=UpdateForm::model()->findByPk(Yii::app()->user->id); и получаем что-то вроде этого

Код: Выделить всё

    public function actionUpdate()
    {
        $model=UpdateForm::model()->findByPk(Yii::app()->user->id);

        if(isset($_POST['ajax']) && $_POST['ajax']==='edit-form')
        {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }

        if(isset($_POST['User']))
        {
            $model->attributes=$_POST['User'];
            if($model->validate() && $model->save())
            {
                Yii::app()->user->setFlash('edit', 'Changes are saved.');
                $this->refresh();
            }
        }

        $this->render('/user/edit',array('model'=>$model));
    }
 
в итоге на странице все поля будут уже заполнены.

Проблема состоит в том, что правила, указанные в моделе UpdateForm не действуют; берутся правила из модели User.
Соответственно встаёт вопрос - то ли я что-то где-то недоделал(чтобы брались нужные правила из UpdateForm); то ли всё корректно и тогда я совершенно не пойму вот этой фразы
"Первый. К этому я склоняюсь. Также как и для actionRegistration() создавать отдельные модели унаследованные от User, единственное что нам требуется это переопределить метод rules()"
а следовательно и всего решения в целом - ведь если так, то это нерабочее решение ведь; то ли я просто не понимаю чего-то более глобального :) подскажите, пожалуйста
Аватара пользователя
because
Сообщения: 689
Зарегистрирован: 2010.09.30, 22:01

Re: Расширение rules() моделей

Сообщение because »

вроде все верно у вас, правила должны браться из модели UpdateForm, только в $_POST вам придет не User а UpdateForm. хотя я не понимаю зачем все это, когда можно обойтись моделью User
RTFM !
netti
Сообщения: 2
Зарегистрирован: 2012.03.13, 22:24

Re: Расширение rules() моделей

Сообщение netti »

Ну вот проблема как раз в том, что правила берутся из User. Если не сложно, проверьте у себя подобный примерчик.
только в $_POST вам придет не User а UpdateForm.
я тоже так сначала в контроллере прописал, а после того как посмотрел исходник странички - там все поля были с именами вида User['username'], User['firstname'],... То есть тут также виджет автоматом проставляет User за место UpdateForm.
то есть если бы мы в этом примере делали $model = new UpdateForm; то правила брались бы из модели UpdateForm и виджет бы проставлял везде UpdateForm['username'], UpdateForm[['firstname'],... А когда идёт $model=UpdateForm::model()->findByPk(Yii::app()->user->id); то всё получается так, как я описал постом выше. Вот я и не понимаю - то ли это корректное поведение(так и должно быть), то ли я что-то не так делаю.


хотя я не понимаю зачем все это, когда можно обойтись моделью User
это тоже для меня вопрос. К примеру в Registration много, где встречал отдельную модель для регистрации, наследовавшую User (в том же модуле yii-user, анонсированном здесь на форуме). И хотелось бы знать под какие задачи целесообразно создавать отдельную модель(наследующую какую-нибудь сущность), а когда в этом смысла нет. (в данном случае задачи регистрации и редактирования аккаунта довольно таки похожи - и хотелось бы как-то научиться чувствовать эту грань, что где лучше использовать)
esche
Сообщения: 1054
Зарегистрирован: 2010.11.24, 03:39

Re: Расширение rules() моделей

Сообщение esche »

netti писал(а):Ну вот проблема как раз в том, что правила берутся из User. Если не сложно, проверьте у себя подобный примерчик.
только в $_POST вам придет не User а UpdateForm.
я тоже так сначала в контроллере прописал, а после того как посмотрел исходник странички - там все поля были с именами вида User['username'],
В новую модель следует добавить

Код: Выделить всё

    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    } 
хотя я не понимаю зачем все это, когда можно обойтись моделью User
это тоже для меня вопрос. К примеру в Registration много, где встречал отдельную модель для регистрации, наследовавшую User (в том же модуле yii-user, анонсированном здесь на форуме). И хотелось бы знать под какие задачи целесообразно создавать отдельную модель(наследующую какую-нибудь сущность), а когда в этом смысла нет. (в данном случае задачи регистрации и редактирования аккаунта довольно таки похожи - и хотелось бы как-то научиться чувствовать эту грань, что где лучше использовать)
Yii (ООП) позволяет сделать так, как удобно. Если удобнее несколько моделей - по 20 строчек кода - можно так (с одной стороны, это более наглядно и не захламляет основную модель временными атрибутами вроде "повтор пароля" или "капча").

Хотя, при размещении в модели User правил для сценария registration|update (в данном случае) строчек добавится меньше, а при аккуратном оформлении кода наглядность не должна уменьшиться.

Если же логика унаследованной модели (UpdateForm) будет достаточно сложной - условно, то на "многоскринов" - (и её нельзя или нет смысла выносить в отдельные валидаторы), конечно, вариант создания отдельной модели более чем оправдан.

Чёткой границы, лично я не вижу - думаю, разработчик вправе оставить это на своё усмотрение.. главное не забывать про маньяка, который будет поддерживать этот код )))
...
Ответить