/ */ class P4Cms_Content_Opened extends P4Cms_Record_Volatile { protected $_storageSubPath = 'opened'; const PING_TIMEOUT = 70; // 2*30 + 10; represents 2 missed pings with a buffer /** * Use this accessor to get all of the keys grouped by user; * e.g. users[user][keyName]. This method will screen out * any entries older than PING_TIMEOUT and adds in 'Offset' * values for the start/ping/edit times. * * Calling getValues on this model will return keys in the * format user-keyName. We store the keys this way to allow * setting a single user/key/value without knowing the other * values (minimizes race conditions). * * @return array the current values organized by user */ public function getUsers() { $users = array(); foreach ($this->getValues() as $key => $value) { $parts = explode('-', $key, 2); if (count($parts) !== 2) { continue; } list($user, $key) = $parts; if (!isset($users[$user])) { $users[$user] = array(); } $users[$user][$key] = $value; } // do a second loop to remove expired entries $time = time(); foreach ($users as $user => &$values) { // normalize array $values += array('pingTime' => null, 'editTime' => null, 'startTime' => null); // if start or ping time are missing, or the ping is expired remove entry if (!$values['startTime'] || !$values['pingTime'] || ($time - $values['pingTime']) > static::PING_TIMEOUT ) { unset($users[$user]); } } // sort the users based on their last edit and start time uasort( $users, function($a, $b) { if ($a['editTime'] || $b['editTime']) { return $a['editTime'] - $b['editTime']; } return $a['startTime'] - $b['startTime']; } ); return $users; } /** * Set the ping time for a specified user. The default time of true * will automatically set the current time. Passing false will clear * the time for the specified user and any other value will be used * unchanged. * * @param string|P4Cms_User $user The user id to set this property on * @param mixed $time The time to use - optional * @return P4Cms_Content_Opened To maintain a fluent interface */ public function setUserPingTime($user, $time = true) { return $this->setUserTimeProperty($user, 'ping', $time); } /** * Set the edit time for a specified user. The default time of true * will automatically set the current time. Passing false will clear * the time for the specified user and any other value will be used * unchanged. * * @param string|P4Cms_User $user The user id to set this property on * @param mixed $time The time to use - optional * @return P4Cms_Content_Opened To maintain a fluent interface */ public function setUserEditTime($user, $time = true) { return $this->setUserTimeProperty($user, 'edit', $time); } /** * Set the start time for a specified user. The default time of true * will automatically set the current time. Passing false will clear * the time for the specified user and any other value will be used * unchanged. * * @param string|P4Cms_User $user The user id to set this property on * @param mixed $time The time to use - optional * @return P4Cms_Content_Opened To maintain a fluent interface */ public function setUserStartTime($user, $time = true) { return $this->setUserTimeProperty($user, 'start', $time); } /** * Set the time for a specified user property. The default time of true * will automatically set the current time. Passing false will clear * the time for the specified user and any other value will be used * unchanged. * * @param string|P4Cms_User $user The user id to set this property on * @param string $property The 'time' property to set (e.g. start/ping) * @param mixed $time The time to use - optional * @return P4Cms_Content_Opened To maintain a fluent interface */ public function setUserTimeProperty($user, $property, $time = true) { // normalize user; like a boss $user = $user instanceof P4Cms_User ? $user->getId() : $user; // default case; use current time if ($time === true) { $time = time(); } // normalize false values to null if (!$time) { $time = null; } return $this->setValue($user . '-' . $property . 'Time', $time); } }