View file vkclone-0.0.1/protected/models/User.php

File size: 10.83Kb
<?php
/**
 * This is the model class for table "{{users}}".
 *
 * The followings are the available columns in table '{{users}}':
 * @property string $id
 * @property string $password_hash
 * @property string $email
 */
class User extends CActiveRecord {

	const MALE = 'male';
	const FEMALE = 'female';

	public $password;
	public $rememberMe = true;
	public $model;

	public $birth_year;
	public $birth_month;
	public $birth_day;

	private $_identity;

	/**
	 * @return string the associated database table name
	 */
	public function tableName() {
		return '{{users}}';
	}

	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules() {
		return array(
			// common rules
			array('email, first_name, last_name, patronymic', 'length', 'max' => 254),
			array('password_hash', 'length', 'max' => 64),
			array('birth_year', 'numerical', 'integerOnly' => true, 'min' => 1900, 'max' => date('Y') - 5),
			array('birth_month', 'numerical', 'integerOnly' => true, 'min' => 1, 'max' => 12),
			array('birth_day', 'numerical', 'integerOnly' => true, 'min' => 1, 'max' => 31),
			array('gender', 'in', 'range' => array('male', 'female')),

			// both
			array('email', 'required', 'on' => 'login, registration'),

			// login
			array('password', 'authenticate', 'on' => 'login'),
			array('password', 'required', 'on' => 'login'),
			array('rememberMe', 'boolean', 'on' => 'login'),

			// registration
			array('password', 'required', 'on' => 'registration'),
			array('email', 'emailAvailable', 'on' => 'registration'),

			// fill name
			array('first_name, last_name', 'required', 'on' => 'fillName'),

			// edit personal info
			array('first_name, last_name, gender', 'required', 'on' => 'edit'),
			array('birth_date', 'checkDate', 'dayAttribute' => 'birth_day', 'monthAttribute' => 'birth_month', 'yearAttribute' => 'birth_year', 'on' => 'edit'),

			// edit site settings
			array('language', 'in', 'range' => array_keys($this->possibleLanguages)),
			array('timezone', 'in', 'range' => array_keys($this->possibleTimezones)),
			array('language, timezone', 'default', 'value' => null),

			array('id, email, password_hash, registrated_at, visited_at', 'safe', 'on' => 'search'),
		);
	}

	/**
	 * @return array relational rules.
	 */
	public function relations() {
		return array(
			'profile' => array(self::BELONGS_TO, 'Profile', 'id'),
			'totalPhotos' => array(self::STAT, 'GalleryPhoto', 'user_id'),
			'totalForumTopics' => array(self::STAT, 'Topic', 'initiator_id'),
			'totalPublics' => array(self::STAT, 'PublicReader', 'user_id'),
			'totalGroups' => array(self::STAT, 'GroupMember', 'user_id'),
			// 'totalFriends' => array(self::STAT, 'UserFriend', 'friend_id', 'condition' => 'totalFriends.user_id = :user OR totalFriends.friend_id = :user', 'params' => array(':user' => $this->id)),
		);
	}

	/**
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels() {
		return array(
			'id' => Yii::t('Users', 'User id'),
			'email' => Yii::t('Users', 'Email'),
			'password_hash' => Yii::t('Users', 'Password hash'),
			'password' => Yii::t('Users', 'Password'),
			'rememberMe' => Yii::t('Users', 'Remember me'),
			'first_name' => Yii::t('Users', 'First name'),
			'last_name' => Yii::t('Users', 'Last name'),
			'patronymic' => Yii::t('Users', 'Patronymic'),
			'gender' => Yii::t('Users', 'Gender'),
			'birth_date' => Yii::t('Users', 'Date of birth'),
			'registrated_at' => Yii::t('Users', 'DateTime of registration'),
			'visited_at' => Yii::t('Users', 'DateTime of last activity'),
			'timezone' => Yii::t('Users', 'Timezone'),
			'language' => Yii::t('Users', 'Language'),
		);
	}

	/**
	 * Authenticates the password.
	 * This is the 'authenticate' validator as declared in rules().
	 */
	public function authenticate($attribute, $params) {
		if (!$this->hasErrors()) {
			$this->_identity = new DatabaseUserIdentity($this->email, $this->password);
			if (!$this->_identity->authenticate())
				$this->addError('password', Yii::t('Users', 'Username or password is wrong.'));
		}
	}

	/**
	 * Checks email availability.
	 */
	public function emailAvailable($attribute, $params) {
		if (!$this->hasErrors()) {
			if (self::model()->findByAttributes(array('email' => $this->$attribute)) !== null)
				$this->addError($attribute, Yii::t('Users', 'Email already used.'));
		}
	}

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

	/**
	 * Logs in the user using the given username and password in the model.
	 * @return boolean whether login is successful
	 */
	public function registrate() {
		$transaction = $this->dbConnection->beginTransaction();
		$profile = new Profile;
		$profile->type = 'user';
		$profile->save();
		$user = new self;
		$user->id = $profile->id;
		$user->email = $this->email;
		$user->password_hash = crypt($this->password, self::blowfishSalt());
		$user->save();
		$transaction->commit();
		return $user;
	}

	/**
	 * Retrieves a list of models based on the current search/filter conditions.
	 *
	 * Typical usecase:
	 * - Initialize the model fields with values from filter form.
	 * - Execute this method to get CActiveDataProvider instance which will filter
	 * models according to data in model fields.
	 * - Pass data provider to CGridView, CListView or any similar widget.
	 *
	 * @return CActiveDataProvider the data provider that can return the models
	 * based on the search/filter conditions.
	 */
	public function search($pageSize) {
		$criteria = new CDbCriteria;

		$criteria->compare('id', $this->id, true);
		$criteria->compare('email', $this->email, true);
		$criteria->compare('password_hash', $this->password_hash, true);
		$criteria->compare('registrated_at', $this->registrated_at, true);
		$criteria->compare('visited_at', $this->visited_at, true);
		$criteria->compare('first_name', $this->first_name, true);
		$criteria->compare('last_name', $this->last_name, true);
		$criteria->compare('patronymic', $this->patronymic, true);

		return new CActiveDataProvider($this, array(
			'criteria' => $criteria,
			'pagination' => array(
				'pageSize' => $pageSize,
			),
			'sort' => array(
				'defaultOrder' => 'visited_at DESC',
			),
		));
	}

	/**
	 * Returns the static model of the specified AR class.
	 * Please note that you should have this exact method in all your CActiveRecord descendants!
	 * @param string $className active record class name.
	 * @return User the static model class
	 */
	public static function model($className=__CLASS__) {
		return parent::model($className);
	}

	/**
	 * Generate a random salt in the crypt(3) standard Blowfish format.
	 * @param int $cost Cost parameter from 4 to 31.
	 * @throws Exception on invalid cost parameter.
	 * @return string A Blowfish hash salt for use in PHP's crypt()
	 */
	static public function blowfishSalt($cost = 13) {
		if (!is_numeric($cost) || $cost < 4 || $cost > 31) {
			throw new Exception("cost parameter must be between 4 and 31");
		}
		$rand = array();
		for ($i = 0; $i < 8; $i += 1) {
			$rand[] = pack('S', mt_rand(0, 0xffff));
		}
		$rand[] = substr(microtime(), 2, 6);
		$rand = sha1(implode('', $rand), true);
		$salt = '$2a$' . sprintf('%02d', $cost) . '$';
		$salt .= strtr(substr(base64_encode($rand), 0, 22), array('+' => '.'));
		return $salt;
	}

	/**
	 * Updates time of last acitivty
	 */
	public function updateVisitTime() {
		$this->visited_at = new CDbExpression('NOW()');
		return $this->save(true, array('visited_at'));
	}

	/**
	 * Checks if user online
	 */
	public function isOnline() {
		return ((time() - Yii::app()->params['onlineStatusLimit']) < strtotime($this->visited_at));
	}

	/**
	 * Named scopes
	 */
	public function scopes() {
		return array(
			'online' => array(
				'order' => 'visited_at DESC',
				'condition' => 'visited_at >= :min_last_acitivty_datetime',
				'params' => array(':min_last_acitivty_datetime' => date('Y-m-d G:i:s', time() - Yii::app()->params['onlineStatusLimit'])),
			),
			'offline' => array(
				'order' => 'visited_at DESC',
				'condition' => 'visited_at < :min_last_acitivty_datetime',
				'params' => array(':min_last_acitivty_datetime' => date('Y-m-d G:i:s', time() - Yii::app()->params['onlineStatusLimit'])),
			),
		);
	}

	/**
	 * Date validator
	 */
	public function checkDate($attribute, $params) {
		if (!$this->hasErrors() && !checkdate($this->{$params['monthAttribute']}, $this->{$params['dayAttribute']}, $this->{$params['yearAttribute']}))
			$this->addError($attribute, Yii::t('Users', 'Date is wrong.'));
		else
			$this->$attribute = $this->{$params['yearAttribute']}.'-'.$this->{$params['monthAttribute']}.'-'.$this->{$params['dayAttribute']};
	}

	/**
	 * Returns localized month names to use it in dropDownList()
	 */
	public function getPossibleMonths() {
		return CLocale::getInstance(Yii::app()->language)->getMonthNames();
	}

	/**
	 * Returns localized language names to use it in dropDownList()
	 */
	public function getPossibleLanguages() {
		$locale = CLocale::getInstance(Yii::app()->language);
		return array(
			null => Yii::t('Users', 'Default site language ({language})', array('{language}' => $locale->getLocaleDisplayName(Settings::instance()->language))),
			'ru' => $locale->getLocaleDisplayName('ru'),
			'en' => $locale->getLocaleDisplayName('en'),
		);
	}

	/**
	 * Returns all known timezones to use it in dropDownList()
	 */
	public function getPossibleTimezones() {
		$default_timezone = Yii::app()->timeZone;
		$lands = require Yii::getPathOfAlias('application.data').'/timezones.php';

		$timezones = array(
			Yii::t('Users', 'Default site timezone ({timezone})', array('{timezone}' => Yii::t('Users', Settings::instance()->timezone))) => '',
		);

		foreach ($lands as $land => $land_timezones)
			$timezones = array_merge($timezones, $land_timezones);
		$timezones = array_flip($timezones);

		foreach ($timezones as $i => $timezone) {
			if (!empty($i))
				date_default_timezone_set($i);
			$timezones[$i] = is_numeric($timezone) ? Yii::t('Users', $i).' '.date('P (G:i)') : $timezone;
		}
		date_default_timezone_set($default_timezone);
		return $timezones;
	}

	/**
	 * Returns compiled name
	 */
	public function getName() {
		return $this->first_name.' '.$this->last_name;
	}

	/**
	 * Add notification to user
	 */
	public function addNotification($text, $type) {
		$notification = new UserNotification;
		$notification->user_id = $this->id;
		$notification->type = $type;
		$notification->text = $text;
		$notification->new = 1;
		return $notification->save();
	}

	/**
	 * Turn off delete() operation.
	 */
	public function beforeDelete() {
		parent::beforeDelete();
		return false;
	}

	public function getTotalFriends() {
		return UserFriend::model()->allUserFriends($this->id)->count('approved = "1"');
	}
}