models Extension contains commonly used, extended models base classes, which is so lacking in Yii for developing good MVC application.

  1. Requirements
  2. Usage
  3. 1. SearchModel base class for modeling select data
  4. 2. FilterModel base class for additional filtering search models' criteria.
  5. 3. RatingModel base class for modeling coefficient based ratings with calculations caching.
  6. 4. FormSubmitModel base class specially for encapsulating form submitting logic into it.
  7. 5. TransactionalFormModel base class used for submitting data into database under transaction. Automatic rollback transaction on exception throw or on submitting error.
  8. 6. DAOModel base class used for submitting data into database under transaction or selecting data. Model implements handling data access code for each access scenario.
  9. Resources

This extensions contains commonly used, extended models for working with database.

Requirements

...requirements of using this extension (e.g. Yii 1.1.10 or above)...

Usage

To use this extension, please, import as needed aliases in application import property.

1. SearchModel base class for modeling select data

Example:

class MySearchModel extends SearchModel
{
    const DEFAULT_PAGE_SIZE = 20;

    const SCOPE_ONLY_ACTIVE = 'only_active';
    const SCOPE_WITH_COMMENTS = 'with_comments';

    public $field_name;

    public function getModelClass()
    {
        return 'Post';
    }

    protected function build()
    {
       $criteria = new CDbCriteria();
       if (isset($this->field_name)) {
           $criteria->compare('t.name', $this->field_name, true);
       }
       if ($this->hasScope(self::SCOPE_ONLY_ACTIVE)) {
           $criteria->compare('t.status', 'active');
       }
       if ($this->hasScope(self::SCOPE_WITH_COMMENTS)) {
           $criteria->with[] = 'comments';
       }
       $criteria->together = true;
       $config = array('criteria' => $criteria);
       return new CActiveDataProvider($this->getModelClass(), $config);
    }
 
    public function getDefaultPageSize()
    {
       return self::DEFAULT_PAGE_SIZE;
    }

    public function getDefualtSortMode()
    {
       return self::SORT_MODE_ALPHABETICAL;
    }

    protected function applySort($criteria)
    {
        switch ($this->sort) {
        case self::SORT_MODE_ALPHABETICAL:
            $criteria->order .= 't.name';
            break;
        case self::SORT_MODE_DATE:
            $criteria->order .= 't.time';
            break;
        }
        parent::applySort($criteria);
    }
}

SearchModel usage:

class MyController extends CController
{
    //...

    public function actionList()
    {
        $model = new MySearchModel();
        $model->addScope(MySearchModel::SCOPE_WITH_COMMENTS);
        if (isset($_POST['MySearchModel'])) {
            $model->attributes = $_POST['MySearchModel'];
        }
        $viewData = array(
            'dataProvider' => $model->search(),
        );
        $this->render('list', $viewData);
    }

    //...
}

2. FilterModel base class for additional filtering search models' criteria.

Example:

class MyTermFilter extends FilterModel
{
    public $term;
    
    public $poi_table_alias;
    
    public function rules()
    {
        return array(
            array('poi_table_alias', 'default', 'value' => 't'),
            array('poi_table_alias, term', 'required'),
            array('term', 'length', 'max' => 512),
            array('term', 'safe', 'on' => self::SCENARIO_FILTERING),
        );
    }
    
    public function applyAttributeFilter($criteria, $attribute)
    {
        switch ($attribute) {
        case 'term':
            $items = explode(',', $this->term);
            $queryCriteria = new CDbCriteria;
            $value = $this->$attribute;
            foreach ($terms as $key => $value) {
                $termCriteria = new CDbCriteria();
                $termCriteria->compare($this->poi_table_alias . '.name', $value, true, 'OR');
                $termCriteria->compare($this->poi_table_alias . '.description', $value, true, 'OR');
                $queryCriteria->mergeWith($termCriteria);
            }
            if ($this->poi_table_alias != 't') {
                $queryCriteria->with = array($this->poi_table_alias);
                $queryCriteria->together = true;
            }
            $criteria->mergeWith($queryCriteria);
            break;
        }
    }
}

Using term filter in SearchModel:

class MySearchModel extends SearchModel
{
    public $term;

    //...

    protected function build()
    {
       $criteria = new CDbCriteria();
       //...
       if (isset($this->term)) {
           $filter = new MyTermFilter();
           $filter->term = $this->term;
           $filter->apply($criteria);
       }
       //...
       $config = array('criteria' => $criteria);
       return new CActiveDataProvider($this->getModelClass(), $config);
    }
}

3. RatingModel base class for modeling coefficient based ratings with calculations caching.

Example:

class UserRating extends RatingModel
{
    const RATING_CACHE_PREFIX = 'user_rating_';
    const DEFAULT_CACHE_DURATION = 1000;
    const DEFAULT_OUTPUT_MULTIPLIER = 1;
    
    public $user;

    public $cacheDuration = self::DEFAULT_CACHE_DURATION;

    public $ratio;
    
    public $multiplier = self::DEFAULT_OUTPUT_MULTIPLIER;

    public function rules()
    {
        return array(
            array('user, ratio, multiplier, cacheDuration', 'required'),
        );
    }
    
    public function getDataCacheId()
    {
        return self::RATING_CACHE_PREFIX . $this->user->id;
    }
    
    public function getDataCacheDuration()
    {
        return $this->cacheDuration;
    }

    protected function calc()
    {
        $ret = 0;
        $ret += $this->_calcFeedbackRating();
        $ret += $this->_calcPhotoRating();
        return round($ret * $this->multiplier);
    }
    
    /**
     * Saves calculated rating into database after calculating
     * 
     * @return void
     * @see RatingModel::afterCalculate()
     */
    protected function afterCalculate()
    {
        parent::afterCalculate();
        $this->user->rating = $this->getCachedValue();
        $this->user->save(true, array('rating'));
    }
    
    /**
     * Calculates user rating based on user's photo rating
     * 
     * @return double poi votes rating
     */
    private function _calcFeedbackRating()
    {
        $connection = $this->user->getDbConnection();
        $query = "
            SELECT SUM(`marks`.value) as `vote` FROM poi_visitor `t`
            INNER JOIN feedback `feedback` ON (`feedback`.user_id = `t`.user_id AND `feedback`.poi_id = `t`.poi_id)
            LEFT JOIN object_mark `marks` ON (`feedback`.id = `marks`.object_id)
            WHERE `t`.user_id = :user_id  AND `marks`.object_type = :object_type;
        ";
        $command = $connection->createCommand($query);
        $params = array(':user_id' => $this->user->id, ':object_type' => ObjectMark::OBJECT_TYPE_FEEDBACK);
        $votesSummary = $command->queryScalar($params);
        $ratio = $this->ratio['feedback'];
        return $ratio * $votesSummary;
    }
    
    
    /**
     * Calculates user rating based on user's photo rating
     * 
     * @return double poi votes rating
     */
    private function _calcPhotoRating()
    {
        $connection = $this->user->getDbConnection();
        $query = "
            SELECT SUM(`marks`.value) as `vote` FROM poi_visitor `t`
            INNER JOIN poi_photo `poi_photo` ON (`poi_photo`.poi_id = `t`.poi_id)
            INNER JOIN photo `photo` ON (`photo`.user_id = `t`.user_id AND `photo`.id = `poi_photo`.photo_id)
            LEFT JOIN object_mark `marks` ON (`photo`.id = `marks`.object_id)
            WHERE `t`.user_id = :user_id  AND `marks`.object_type = :object_type;
        ";
        $command = $connection->createCommand($query);
        $params = array(':user_id' => $this->user->id, ':object_type' => ObjectMark::OBJECT_TYPE_PHOTO);
        $votesSummary = $command->queryScalar($params);
        $ratio = $this->ratio['photo'];
        return $ratio * $votesSummary;
    }
}

Example usage:

class User extends CActiveRecord
{
    //...    

    /**
     * Returns user's rating value
     * 
     * @param boolean $refresh whether required to refresh cached rating value (recalculate)
     * 
     * @return integer user's rating value
     */
    public function getRating($refresh = false)
    {
        if (!$this->isNewRecord) {
            $model = new UserRating;
            $model->attributes = Yii::app()->params['rating']['user'];
            $model->user = $this;
            $value = $model->getValue($refresh);
            return $value;
        }
        return $this->getAttribute('rating');
    }

    //...
}

4. FormSubmitModel base class specially for encapsulating form submitting logic into it.

Example:

class LoginForm extends FormSubmitModel
{
    public $username;
 
    public $password;

    public $rememberMe;

    private $_identity;

    public function rules()
    {
        return array(
            array('username, password', 'required'),
            array('rememberMe', 'boolean'),
            array('password', 'authenticate'),
        );
    }

    public function attributeLabels()
    {
        return array(
            'username' => Yii::t('app', 'User Name'),
            'password' => Yii::t('app', 'Password'),
            'rememberMe' => Yii::t('app', 'Remember me next time'),
        );
    }


    public function authenticate($attribute, $params)
    {
        if (!$this->hasErrors()) {
            $this->_identity = new UserIdentity($this->username, $this->password);
            $this->_identity->authenticate();
            switch($this->_identity->errorCode) {
            case UserIdentity::ERROR_EMAIL_INVALID:
                $this->addError('username', Yii::t('app', 'Email is incorrect.'));
                break;
            case UserIdentity::ERROR_PASSWORD_INVALID:
                $this->addError('password', Yii::t('app', 'Password is incorrect.'));
                break;
            }
        }
    }

    /**
     * Logs in the user using the given username and password in the model.
     *
     * @return boolean whether login is successful
     */
    protected function onSubmit()
    {
        if ($this->_identity->errorCode === UserIdentity::ERROR_NONE) {
            $duration = $this->rememberMe ? 3600 * 24 * 365 : 0; // 30 days
            Yii::app()->user->login($this->_identity, $duration);
            return true;
        } else {
            return false;
        }
    }
}

Example usage:

class AuthController extends CController
{
    //...    

    /**
     * Handles login form
     *
     * @return void
     */
    public function actionLogin()
    {
        $model = new LoginForm;    
        if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
        if (isset($_POST['LoginForm'])) {
            $model->attributes = $_POST['LoginForm'];
            if ($model->submit()) {
                $this->redirect(Yii::app()->user->homeUrl);
            }
        }
        $this->render('login', array('model' => $model));
    }

    //...
}

5. TransactionalFormModel base class used for submitting data into database under transaction. Automatic rollback transaction on exception throw or on submitting error.

Example:

class RegistrationForm extends TransactionalFormModel
{   
    public $username;
    
    public $email;
    
    public $password;
    
    public $verifyPassword;
    
    public $verifyCode;

    public function rules()
    {
        return array(
            array('username, password, verifyPassword, email', 'required'),
            array('email', 'email'),
            array('verifyPassword', 'compare', 'compareAttribute' => 'password',
                'message' => Yii::t('app', 'Retype Password is incorrect.'),
            ),
            array('verifyCode', 'captcha', 'allowEmpty' => false),
        );
    }

    /**
     * Registers new user under database transaction.
     * If something would be wrong, model rollbacks
     * transaction automatically. For manual rollback
     * transaction return false.
     * 
     * @return whether user registered successfully
     * @see FormSubmitModel::onSubmit()
     */
    protected function onSubmit()
    {
        $user = new User();
        $user->username = $this->username;
        $user->email = $this->email;
        $user->password = md5($this->password);
        $user->status = User::STATUS_NOT_VERIFIED;
        if ($user->save()) {
            $profile = new UserProfile();
            $profile->attributes = $this->getAttributes();
            $profile->user_id = $user->id;
            if ($profile->save()) {
                return true;
            } else {
                $this->addErrors($profile->getErrors());
            }
        } else {
            $this->addErrors($user->getErrors());
        }
        return false;
    }
    
    //...
}

6. DAOModel base class used for submitting data into database under transaction or selecting data. Model implements handling data access code for each access scenario.

Examples in preparing stage

Resources

...external resources for this extension...

5 0
22 followers
960 downloads
Yii Version: 1.1
License: BSD-2-Clause
Category: Database
Developed by: djvibegga
Created on: May 17, 2012
Last updated: 10 years ago

Downloads

show all

Related Extensions