Blame | Last modification | View Log | Download
<?php namespace ProcessWire;/*** An individual notification item to be part of a NotificationArray for a Page** @class Notification** @property int $pages_id page ID notification is for (likely a User page)* @property int $sort sort value, as required by Fieldtype* @property int $src_id page ID when notification was generated* @property string $title title/headline* @property int $flags flags: see flag constants* @property int $created datetime created (unix timestamp)* @property int $modified datetime created (unix timestamp)* @property int $qty quantity of times this notification has been repeated* @property array $flagNames Notification flag names** data encoded vars, all optional* ===============================* @property int $id unique ID (among others the user may have)* @property string $text extended text* @property string $html extended text as HTML markup* @property string $from "from" text where applicable, like a class name* @property string $icon fa-icon when applicable* @property string $href clicking notification goes to this URL* @property int $progress progress percent 0-100* @property int $expires datetime after which will automatically be deleted**/class Notification extends WireData {/*** Flag constants for Notification objects** Note that flags 2-32 line up with the same flags from Notice objects**/const flagDebug = 2; // Show/save only when the system is in debug modeconst flagLog = 8; // save to log and showconst flagLogOnly = 16; // save to log but don't showconst flagAllowMarkup = 32; // allow markup in the titleconst flagMessage = 64; // informationalconst flagWarning = 4; // warningconst flagError = 128; // errorconst flagNotice = 256; // Show only as a single-request notice (not stored in DB)const flagSession = 512; // Notification lasts for only this session (not stored in DB)const flagEmail = 1024; // title and body will also be emailed to user (if page is user)const flagOpen = 2048; // notification will automatically open the text/html area (no click required)const flagNoGhost = 4096; // disable showing of a notification ghostconst flagAnnoy = 8192; // rather than just update bug counter, notification will pop up at top of screenconst flagShown = 16384; // has this flag once the notification has been sent to the UI at least onceconst flagAlert = 32768; // show an alert that requires acknowledgement (use with flagSession only)/*** Provides a name for each of the flags** @var array**/static protected $_flagNames = array(self::flagDebug => 'debug',self::flagLog => 'log',self::flagLogOnly => 'log-only',self::flagAllowMarkup => 'markup',self::flagMessage => 'message',self::flagWarning => 'warning',self::flagError => 'error',self::flagNotice => 'notice',self::flagSession => 'session',self::flagEmail => 'email',self::flagOpen => 'open',self::flagNoGhost => 'no-ghost',self::flagAnnoy => 'annoy',self::flagShown => 'shown',self::flagAlert => 'alert',);/*** Page that this Notification belongs to** @var Page**/protected $page;/*** Construct a new Notification**/public function __construct() {// db native vars$this->set('pages_id', 0); // page ID notification is for (likely a User page)$this->set('sort', 0); // sort value, as required by Fieldtype$this->set('src_id', 0); // page ID when notification was generated$this->set('title', ''); // title/headline$this->set('flags', 0); // flags: see flag constants$this->set('created', 0); // datetime created (unix timestamp)$this->set('modified', 0); // datetime created (unix timestamp)$this->set('qty', 1); // quantity of times this notification has been repeated// data encoded vars, all optional$this->set('id', ''); // unique ID (among others the user may have)$this->set('text', ''); // extended text$this->set('html', ''); // extended text as HTML markup$this->set('from', ''); // "from" text where applicable, like a class name$this->set('icon', ''); // fa-icon when applicable$this->set('href', ''); // clicking notification goes to this URL$this->set('progress', 0); // progress percent 0-100$this->set('expires', 0); // datetime after which will automatically be deleted}/** Fluent interface methods**/public function title($value) { return $this->set('title', $value); }public function text($value) { return $this->set('text', $value); }public function html($value) { return $this->set('html', $value); }public function from($value) { return $this->set('from', $value); }public function icon($value) { return $this->set('icon', $value); }public function href($value) { return $this->set('href', $value); }public function progress($value) { return $this->set('progress', $value); }public function expires($value) { return $this->set('expires', $value); }public function flag($value) { return $this->setFlag($value, true); }public function flags($value) { return $this->setFlags($value, true); }/*** Does this Notification match the given flag name(s)?** @param string $name* @return bool**/public function is($name) {$flags = $this->flagNamesToFlags($name);$is = 0;foreach($flags as $flag) {if($this->flags & $flag) $is++;}return $is == count($flags);}/*** Given a flag name, return the corresponding flag value** @param string $name* @return int mixed* @throws WireException if given unknown flag**/protected function flagNameToFlag($name) {if(is_string($name)) {$flag = array_search($name, self::$_flagNames);if(!$flag) throw new WireException("Unknown flag: $name");} else {$flag = $name;if(!isset(self::$_flagNames[$flag])) throw new WireException("Unknown flag: $flag");}return $flag;}/*** Given multiple space separated flag names, return array of flag values** @param string $names space separted, will also accept CSV* @return array of flag name => flag value**/protected function flagNamesToFlags($names) {if(strpos($names, ',') !== false) $names = str_replace(',', ' ', $names);$names = explode(' ', $names);$flags = array();foreach($names as $name) {if(empty($name)) continue;$flag = $this->flagNameToFlag($name);if($flag) $flags[$name] = $flag;}return $flags;}/*** Set a named flag** @param string|int $name Flag to set* @param bool $add True to add flag, false to remove* @return self**/public function setFlag($name, $add = true) {$flag = ctype_digit("$name") ? (int) $name : $this->flagNameToFlag($name);$flags = parent::get('flags');if($add) {// add flagif($flags & $flag) {// flag is already set} else {$flags = $flags | $flag;parent::set('flags', $flags);}} else {// remove flagif($flags & $flag) {// flag is set, remove it$flags = $flags & ~$flag;parent::set('flags', $flags);} else {// flag is not set}}return $this;}/*** Add the given flag name(s) (shortcut for setFlag)** @param string $name One or more space-separated flag names* @return self**/public function addFlag($name) {return $this->setFlags($name, true);}/*** Remove the given flag name(s) (shortcut for setFlag)** @param string $name One or more space-separated flag names* @return self**/public function removeFlag($name) {return $this->setFlags($name, false);}/*** Set multiple flags** @param string $names space separated string of flag names* @param bool $add True to add, false to remove* @return self**/public function setFlags($names, $add = true) {if(ctype_digit("$names")) {// likely a flag or combined flags in bitmask$flags = (int) $names;// iterate through known flags to see which are setforeach(self::$_flagNames as $flag => $name) {// if it's a recognized/valid flag, set itif($flags & $flag) $this->setFlag($flag, $add);}return $this;}// optimization if this was called with just one flag nameif(strpos($names, ',') === false && strpos($names, ' ') === false) {$this->setFlag($names, $add);}// named flags$flags = $this->flagNamesToFlags($names);foreach($flags as $name => $flag) {$this->setFlag($flag, $add);}return $this;}/*** Set a value to the Notification** Note: setting the 'expires' value accepts either a future date, or a quantity of seconds* in the future relative to now.** @param string $key* @param mixed $value* @return self|Notification|WireData**/public function set($key, $value) {if($key == 'page') {$this->page = $value;return $this;} else if($key == 'created' || $key == 'modified' || $key == 'expires') {// convert date string to unix timestampif($value && !ctype_digit("$value")) $value = strtotime($value);// sanitized date value is always an integer$value = (int) $value;if($key == 'expires' && $value > 0 && $value < strtotime("-10 YEARS")) {// assume this is a time relative to now$value = time() + $value;}} else if($key == 'title') {if($this->flags & self::flagAllowMarkup) {// accept value as-is} else {// regular text sanitizer$value = $this->sanitizer->text($value);}} else if($key == 'from') {// regular text sanitizer$value = $this->sanitizer->text($value);} else if($key == 'text') {// regular text sanitizer$value = $this->sanitizer->textarea($value);} else if(in_array($key, array('pages_id', 'sort', 'src_id', 'flags', 'progress'))) {$value = (int) $value;}return parent::set($key, $value);}/*** Return an ID string/hash unique to this Notification within the page that its on** The text/html, modified date, expires date, and icon may change without affecting the id.** @return mixed|null|string**/public function getID() {$id = parent::get('id');if($id) return $id;$id = parent::get('title') . ',' .parent::get('created') . ',' .parent::get('from') . ',' .parent::get('src_id') . ',' .($this->page ? $this->page->id : '?'); // . ',' .//parent::get('flags');return 'noID' . md5($id);}/*** Return an string hash for comparing other notifications to see if they contain the same content** Hash specifically excludes consideration of dates (created, modified, expires)** @return string**/public function getHash() {$id = trim(parent::get('title')) . ',' .// parent::get('from') . ',' .// parent::get('src_id') . ',' .// ($this->page ? $this->page->id : '?') . ',' .// parent::get('flags') . ',' .// parent::get('icon') . ',' .trim(parent::get('text')) . ',' .trim(parent::get('html'));return md5($id);}/*** Retrieve a value from the Notification** @param string $key* @return mixed**/public function get($key) {if($key == 'id') return $this->getID();if($key == 'page') return $this->page;if($key == 'hash') return $this->getHash();if($key == 'flagNames') {$flags = parent::get('flags');$flagNames = array();foreach(self::$_flagNames as $val => $name) {if($flags & $val) $flagNames[$val] = $name;}return $flagNames;}$value = parent::get($key);// if the page's output formatting is on, then we'll return formatted valuesif($this->page && $this->page->of()) {if($key == 'created' || $key == 'expires' || $key == 'modified') {// format a unix timestamp to a date string$value = date('Y-m-d H:i:s', $value);} else if($key == 'title' || $key == 'text' || $key == 'from') {// return entity encoded versions of stringsif($key == 'title' && ($this->flags & self::flagAllowMarkup)) {// leave title alone when markup is allowed} else {$value = $this->sanitizer->entities($value);}}} else {if($key == 'created' && !$value) $value = time();}return $value;}/*** Is this Notification expired?** @return bool**/public function isExpired() {return ($this->expires > 0 && $this->expires <= time());}/*** String value of a Notification** @return string**/public function __toString() {$str = $this->title;$str .= " (" . implode(', ', $this->get('flagNames')) . ")";return $str;}}