Ответы пользователя по тегу Yii
  • Yii как сделать разные авторизации в разных модулях?

    XAKEPEHOK
    @XAKEPEHOK
    Была подобная ситуация. Слишком много проблем от одновременных авторизаций в рамках одного экземпляра приложения. Попробуйте разбить приложения на части в соответствии с www.yiiframework.com/wiki/63 так у вас одна часть приложения не будет зависеть от другой, и настроить все сможете без проблем
    Ответ написан
    Комментировать
  • Yii: rules и очень много сценариев, в которых чёрт ногу сломит?

    XAKEPEHOK
    @XAKEPEHOK Автор вопроса
    Новое решение: отделить сценарии от правил валидации. Решил разом все свои проблемы

    Расширил ActiveRecord
    class ActiveRecord extends CActiveRecord {
      protected $modelRules = [];
    
      ...
    
      /**
       * @return array общие (базовые для модели) правила валидации, описанные в формате
       * array(
       *   'login' => array(
       *     ['required'],
       *     ['length', 'max' => 200]
       *   ),
       *   'firstName' => array(
       *     ['required'],
       *     ['length', 'max' => 200]
       *   ),
       * )
       */
      public function baseRules()
      {
        return array();
      }
    
      /**
       * @return array список сценариев с установленными правилами валидации для каждого сценария.
       * Правила валидации берутся из массива @see baseRules()
       * 'createUser' => ['login','firstName']
       * Существует возможность задать индивидуальные правила валидации для отдельного поля в заданном сценарии. Например:
       * 'createUser' => array(
       *   'login',
       *   'firstName' => array(
       *     '*', //можем унаследовать правила из @see baseRules()
       *     ['!required'], //можем удалить валидатор "required", указанный в @see baseRules() при наследовании правил
       *     ['in', 'range' => array('Alex','Jack','Sam','Jane')], //и добавляем новое правило
       *   ),
       * )
       */
      public function scenarioRules()
      {
        return array();
      }
    
      /**
       * Формирует валидатор в соотстветствии с требованиями Yii
       * @param $field string поле модели
       * @param $validator array массив с параметрами валидатора
       * @param $scenario string сценарий
       */
      protected function addBaseRule($field,$validator,$scenario)
      {
        $validatorName = [];
        preg_match('/^(!)?([^!]+)/',$validator[0],$validatorName);
        $validator[0] = $validatorName[2];
        $ruleKey = $field.'_'.$validator[0].'_'.$scenario;
    
        if (empty($validatorName[1])) {
          if (!empty($scenario)) $validator['on'] = $scenario;
          $validator[1] = $validator[0];
          $validator[0] = $field;
          $this->modelRules[$ruleKey] = $validator;
        } else unset($this->modelRules[$ruleKey]);
      }
    
      /**
       * Формирует валидатор в соотстветствии с требованиями Yii из массива @see baseRules()
       * @param $field string поле модели
       * @param $scenario string сценарий
       */
      protected function addBaseRules($field,$scenario)
      {
        $baseRules = $this->baseRules();
        if (isset($baseRules[$field])) foreach($baseRules[$field] as $validator) $this->addBaseRule($field,$validator,$scenario);
      }
    
      public function rules()
      {
        $this->modelRules = [];
        $scenarioRules = $this->scenarioRules();
        if (empty($scenarioRules)) $scenarioRules = [''];
        foreach ($scenarioRules as $scenario => $rules) {
          //Если сценариев нет, то устанавливаем общие для всех правила
          if ($scenario == 0 && empty($rules)) $rules = array_keys($this->baseRules());
          foreach ($rules as $field => $rule) {
            //Если в сценариях заданы правила
            if (is_array($rule)) {
              //Добавляем родительские правила, если есть «*»
              if (in_array('*',$rule)) $this->addBaseRules($field,$scenario);
              foreach ($rule as $validator) {
                //Проверяем, что правило не является маской. Т.е. «*»
                if (is_array($validator)) $this->addBaseRule($field,$validator,$scenario);
              }
            } else $this->addBaseRules($rule,$scenario);
          }
        }
        foreach ($this->modelRules as &$rule) uksort($rule,function($a,$b){
          if (is_numeric($a) && is_numeric($b) && $a>$b) return 1;
          return is_numeric($a) ? -1 : 1;
        });
        return $this->modelRules;
      }


    В итоге получил такую модель User
    class User extends CActiveRecord {
    
      public $currentPassword;
      public $retypePassword;
    
      pulbic function baseRules()
      {
        return array(
          'login' => array(
            array('required')
            array('length', 'max' => 80),
            array('unique'),
            array('match', 'pattern' => '~^[\da-zа-яёА-ЯЁ\.\-@_\+]+$~i'),
          ),
          'email' => array(
            array('length', 'max' => 200),
            array('unique'),
            array('email'),
            array('required'),
          ),
          'password' => array(
            array('required'),
          ),
          'currentPassword' => array(
            array('required'),
            array('passwordValidator'),
          ),
          'retypePassword' => array(
            array('required'),
            array('compare','compareAttribute' => 'password'),
          ),
          'phone' => array(
            array('length', 'max' => 12),
          ),
          'icq' => array(
            array('length', 'max' => 9),
          ),
        );
      }
    
      pulbic function scenarios()
      {
        return array(
          'registration' => array('login','email','icq','phone'),
          'updateByAdmin' => array(
            'login',
            'email',
            'icq',
            'phone',
            'password' => array(
              array('default'),
            )
          ),
          'updateByModerator' => array('email','icq','phone'),
          'changeEmail' => array('email','currentPassword'),
          'changePassword' => array('password','retypePassword','currentPassword'),
        );
      }
    }


    Расширенный AR формирует типичный для Yii массив rules, используя данные из методов scenarios() и baseRules()
    Ответ написан
    Комментировать
  • Поиск похожих по тегам постов в блоге на Yii?

    XAKEPEHOK
    @XAKEPEHOK
    Вряд ли вопрос еще актуален, но посмотрите на github.com/yiiext/taggable-behavior
    Ответ написан
    Комментировать
  • Хороший алгоритм для создания динамической формы регистрации?

    XAKEPEHOK
    @XAKEPEHOK
    Сталкивался с подобной ситуацией. Сохраняйте данные в localStorage (все равно у вас все построение на JS) и потом, когда все параметры заданы постите на сервер. Так ничего не потеряется
    Ответ написан
    Комментировать
  • UPPERCASE сохранение в бд?

    XAKEPEHOK
    @XAKEPEHOK
    И есть еще вариант: сохранять в любом регистре, а при выборке перекрывать afterFind
    protected function afterFind() {
        parent::afterFind();
        $this->field = strtoupper($this->field);
    }
    
    Ответ написан
    2 комментария
  • Подобрать архитектуру распределённого Yii-приложения?

    XAKEPEHOK
    @XAKEPEHOK
    У меня похожая ситуация. Разрабатываю SaaS приложение, где много пользователей, при этом каждый сам себе король, у каждого своя нумерация (id) и т.д. и т.п. Тоже думал про несколько баз, но в результате решил использовать одну базу

    В БД к таблицам добавляю поля (int) personalID и projectID, а дальше наследуюсь вот от этого класса
    abstract class PersonalActiveRecord extends CActiveRecord
    {
      public $usePersonalID = true; // Использовать ли персональную нумерацию
      public $personalID = null;
      public $projectID = null;
    
      protected function personalIdExpression(){
        $sql =
          'COALESCE((SELECT personalID FROM
            (SELECT (MAX(personalID)+1) as personalID FROM '.$this->tableName().' WHERE projectID = '.$this->projectID.')
          as personalID ),1)';
        return new CDbExpression($sql);
      }
    
      protected function beforeSave(){
        if (!parent::beforeSave()) return false;
          if ($this->isNewRecord) {
            $this->projectID = (int)Y::param('projectID');
            if ($this->usePersonalID)
              if ($this->personalID===null) $this->personalID = $this->personalIdExpression();
          }
        return true;
      }
    
      public function defaultScope() {
        return array(
          'condition'=>"projectID='".(int)Y::param('projectID')."'",
        );
      }
    
    }
    
    Ответ написан
    Комментировать
  • Excel и Yii....?

    XAKEPEHOK
    @XAKEPEHOK
    А что вам мешает написать свою обертку на Yii для PHP Excel?
    Ответ написан
  • Yii и Smarty-renderer

    XAKEPEHOK
    @XAKEPEHOK Автор вопроса
    Сам спросил, сам ответил.
    Yii::app()->viewRenderer->getSmarty()->setTemplateDir(Y::alias('webroot.themes.'.Y::param('domain')));
    $this->render('webroot.themes.'.Y::param('domain').'.index', array('page' => $page));
    
    Ответ написан
    Комментировать
  • Yii: выбор сценария в зависимости от операций в RBAC?

    XAKEPEHOK
    @XAKEPEHOK Автор вопроса
    Я только сегодня более ли менее разобрался с RBAC в Yii. Подскажите пожалуйста как мне поступить в такой ситуации. Есть модель Users, которая имеет поля Username, Password, Email, Rating, Banned, RealName, About.
    Для редактирования профиля пользователя используется одна и та же форма, некоторые поля которой скрываются в зависимости от прав пользователя. Сам пользователь может менять только свои Password, Email, RealName и About. Пользователь с правами модератора может менять все те же поля + banned для любого пользователя системы. Ну а пользователь с правами администратора может менять вообще любые поля любого пользователя.
    Все бы хорошо, но количество групп пользователей и их привилегий может меняться. Например, может появиться супер-модератор, который может менять все то же, что и модератор + Rating.
    При отправки данных из формы модель AR сохраняет только те данные, которые прописаны в rules самой модели. ТО, что не прописано — игнорируется. Т.е. просто скрывать поля нельзя, т.к. подделать любой POST запрос легко. Здесь нужно колдовать со сценариями, но делать что-то типа
    if (Yii::app()->user->checkAccess('changeUsername') && Yii::app()->user->checkAccess('changeRating')) $model->setScenario('changeUsernameRating');
    if (Yii::app()->user->checkAccess('changeUsername') && Yii::app()->user->checkAccess('changeBanned')) $model->setScenario('changeUsernameBanned');
    

    совсем не хочется, т.к. получается громоздкий и запутанный огород
    Ответ написан