File: /var/www/apklausos/application/models/Notification.php
<?php
/**
* This is the model class for table "{{notifications}}".
*
* The following are the available columns in table '{{notifications}}':
* @property integer $id
* @property string $entity survey or user
* @property string $entity_id survey ID or user id
* @property string $title
* @property string $message
* @property string $status new, read
* @property integer $importance 1 or 3. 3 will show popup on page load, 2 is reserved for future bell animation.
* @property string $display_class warning, danger, success
* @property string $hash
* @property string $created When the notification was created
* @property string $first_read When the notification was read
*/
class Notification extends LSActiveRecord
{
const NORMAL_IMPORTANCE = 1; // Just notification in admin menu
const NAG_ONCE_IMPORTANCE = 2; // Like 3 but always only shown once.
const HIGH_IMPORTANCE = 3; // Popup on page load
/**
* See example usage at manual page: https://www.limesurvey.org/manual/Notifications#Examples
* @param array<string, mixed>|string|null $options If string then scenario
*/
public function __construct($options = null)
{
// Don't do anything if this is called from self::model()
if (is_string($options) || is_null($options)) {
parent::__construct($options); // $options = scenario in this case
return;
} else {
// Why not Zoidberg? (\/) (°,,,°) (\/)
parent::__construct();
}
$options = $this->checkShortcuts($options);
$this->checkMandatoryFields($options, array(
'entity',
'entity_id',
'title',
'message',
));
// Only allow 'survey' or 'user' as entity
if ($options['entity'] != 'survey' && $options['entity'] != 'user') {
throw new InvalidArgumentException('Invalid entity: ' . $options['entity']);
}
// Default to 'default' display class
if (!isset($options['display_class'])) {
$options['display_class'] = 'default';
}
// Default to 'log' notification importance
if (!isset($options['importance'])) {
$options['importance'] = self::NORMAL_IMPORTANCE;
}
// importance must be between 1 and 3
if ($options['importance'] < 1 && $options['importance'] > 3) {
throw new InvalidArgumentException('Invalid importance: ' . $options['importance']);
}
// Set everything up
$this->entity = $options['entity'];
$this->entity_id = $options['entity_id'];
$this->title = $options['title'];
$this->message = $options['message'];
$this->display_class = $options['display_class'];
$this->importance = $options['importance'];
$this->status = 'new';
$this->created = date('Y-m-d H:i:s', time());
$this->first_read = null;
}
/**
* Some shortcuts for easier use
* @param array<string, mixed>
* @return mixed
*/
protected function checkShortcuts($options)
{
// Shortcuts for entity id
if (isset($options['survey_id'])) {
$options['entity'] = 'survey';
$options['entity_id'] = $options['survey_id'];
} elseif (isset($options['user_id'])) {
$options['entity'] = 'user';
$options['entity_id'] = $options['user_id'];
}
return $options;
}
/**
* Check so all mandatory fields are defined when constructing
* a new notification.
* @param array<string, string> $options
* @param string[] $mandatory
* @return void
* @throws InvalidArgumentException
*/
protected function checkMandatoryFields(array $options, array $mandatory)
{
foreach ($mandatory as $mand) {
if (!isset($options[$mand]) || $options[$mand] == '') {
throw new InvalidArgumentException('Field ' . $mand . ' is mandatory for notification');
}
}
}
/** @inheritdoc */
public function tableName()
{
return '{{notifications}}';
}
/** @inheritdoc */
public function primaryKey()
{
return 'id';
}
/** @inheritdoc */
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('entity_id', 'numerical', 'integerOnly' => true),
array('entity', 'length', 'max' => 64),
array('title', 'length', 'max' => 255),
array('message, created, first_read', 'safe'),
// The following rule is used by search().
// @todo Please remove those attributes that should not be searched.
array('id, entity, entity_id, message, importance, created, first_read, status, title', 'safe', 'on' => 'search'),
);
}
/** @inheritdoc */
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
);
}
/** @inheritdoc */
public function attributeLabels()
{
return array(
'id' => gT('ID'),
'entity' => gT('Entity'),
'entity_id' => gT('Entity'),
'message' => gT('Message'),
'importance' => gT('Importance'),
'created' => gT('Created'),
'first_read' => gT('Read'),
'status' => gT('Status'),
'title' => gT('Title'),
);
}
/** @inheritdoc */
public function search()
{
// @todo Please modify the following code to remove attributes that should not be searched.
$criteria = new CDbCriteria();
$criteria->compare('id', $this->id);
$criteria->compare('entity', $this->entity, true);
$criteria->compare('entity_id', $this->entity_id);
$criteria->compare('message', $this->message, true);
$criteria->compare('importance', $this->importance);
$criteria->compare('created', $this->created, true);
$criteria->compare('first_read', $this->first_read);
$criteria->compare('status', $this->status, true);
$criteria->compare('title', $this->title, true);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
/**
* Returns a URL to the Ajax action in notification controller
* Used when user clicks on a notification link
* @return string
*/
public function getAjaxUrl()
{
return Yii::app()->createUrl(
'admin/notification',
array(
'sa' => 'getNotificationAsJSON',
'notId' => $this->id
)
);
}
/**
* Url that is used to mark that user read the message
* @return string
*/
public function getReadUrl()
{
return Yii::app()->createUrl(
'admin/notification',
array(
'sa' => 'notificationRead',
'notId' => $this->id
)
);
}
/**
* Mark notification as read NOW()
* @return boolean Result of update
*/
public function markAsRead()
{
$this->first_read = date('Y-m-d H:i:s', time());
$this->status = 'read';
$result = $this->update();
return $result;
}
/**
* Url to fetch the complete notification menu widget
* @param int|null $surveyId
* @return string
*/
public static function getUpdateUrl($surveyId = null)
{
$params = array(
'sa' => 'actionGetMenuWidget',
);
if ($surveyId) {
$params['surveyId'] = $surveyId;
}
return Yii::app()->createUrl(
'admin/notification',
$params
);
}
/**
* @inheritdoc
* @return Notification the static model class
*/
public static function model($className = __CLASS__)
{
/** @var self $model */
$model = parent::model($className);
return $model;
}
/**
* Get latest notifications to show in the menu
* @param int|null $surveyId
* @return Notification[]
*/
public static function getNotifications($surveyId)
{
// TODO : via survey relations
$criteria = self::getCriteria($surveyId);
$nots = self::model()->findAll($criteria);
return $nots;
}
/**
* Get notifications of importance HIGH_IMPORTANCE
* @param int|null $surveyId
* @return Notification[]
*/
public static function getImportantNotifications($surveyId)
{
// TODO this should be in Survey model (relations?)
$criteria = self::getCriteria($surveyId);
$criteria2 = new CDbCriteria();
$criteria2->addCondition('importance = ' . self::HIGH_IMPORTANCE);
$criteria->mergeWith($criteria2, 'AND');
return self::model()->findAll($criteria);
}
/**
* Count how many notifications we have
* @param int|null $surveyId
* @return string
*/
public static function countNotifications($surveyId)
{
// TODO this should be in Survey model
$criteria = self::getCriteria($surveyId);
$nr = self::model()->count($criteria);
return $nr;
}
/**
* Returns number of notifications with status 'new'
* @param int|null $surveyId
* @return string
*/
public static function countNewNotifications($surveyId)
{
$criteria = self::getCriteria($surveyId);
$criteria2 = new CDbCriteria();
$criteria2->addCondition('status = \'new\''); // TODO: Check first_read = null instead?
$criteria->mergeWith($criteria2, 'AND');
$nr = self::model()->count($criteria);
return $nr;
}
/**
* Count important notifications
* @param int|null $surveyId
* @return string
*/
public static function countImportantNotifications($surveyId)
{
$criteria = self::getCriteria($surveyId);
$criteria2 = new CDbCriteria();
$criteria2->addCondition('importance = ' . self::HIGH_IMPORTANCE . ' OR ' . 'importance = ' . self::NAG_ONCE_IMPORTANCE);
$criteria->mergeWith($criteria2, 'AND');
return self::model()->count($criteria);
}
/**
* Criteria to fetch all notifications for this survey and this user
* @param int|null $surveyId
* @return CDbCriteria
*/
protected static function getCriteria($surveyId = null)
{
$criteria = new CDbCriteria();
$params = array();
// Only fetch survey specific notifications if user is viewing a survey
if (!empty($surveyId)) {
$criteria->addCondition('entity =:sentity AND entity_id=:sentity_id');
$params[':sentity'] = 'survey';
$params[':sentity_id'] = $surveyId;
}
// User notifications
$criteria->addCondition('entity =:uentity AND entity_id=:uentity_id', 'OR');
$params[':uentity'] = 'user';
$params[':uentity_id'] = Yii::app()->user->id;
// Only get new notifications
//$criteria3 = new CDbCriteria();
//$criteria3->addCondition('status = \'new\''); // TODO: read = null?
//$criteria->mergeWith($criteria3, 'AND');
$criteria->params = $params;
$criteria->order = 'id DESC';
$criteria->limit = 50;
return $criteria;
}
/**
* Broadcast a message to all users
* See example usage at manual page: https://www.limesurvey.org/manual/Notifications#Examples
* @param array $options
* @param array $users
*/
public static function broadcast(array $options, array $users = null)
{
// Get all users if no $users were given
if ($users === null) {
$users = User::model()->findAll();
}
foreach ($users as $user) {
$options['user_id'] = $user->uid;
$not = new Notification($options);
$not->save();
}
}
}