_selectOptions['order'] = 'createdAt DESC'; $this->_selectOptions['limitPage'] = [0, (int)$this->getConfig('showCount', 10)]; return $this; } protected function _getFromColumns() { return ['id', 'tweetId', 'userId', 'name', 'screenName', 'imageUrl', 'retwittedByName', 'retwittedByScreenName', 'createdAt', 'html']; } protected function _prepareRow(array &$row) { parent::_prepareRow($row); $row['timeAgo'] = $this->_getTimeAgo($row['createdAt']); return $this; } /** * Returns last twit in DB (for any user) * @return mixed */ protected function _getLastTweet() { $select = $this->_db->select(); $select->from($this->_getPair()); $select->order('createdAt DESC'); $select->limit(1); return $this->_db->fetchRow($select); } /** * Reads latest tweets from users timeline and inserts its to DB * @return bool */ public function updateTweets() { if (null == ($tweets = $this->readTimeline())) { $this->_addError(static::MSG_NO_TWEETS); return true; } $tweets = $this->_convertTweets($tweets); $this->_db->beginTransaction(); try { $this->_getTable()->delete([]); foreach ($tweets as $tweet) { $tweet['raw'] = serialize($tweet['raw']); $this->_getTable()->insert($tweet); } $this->_db->commit(); } catch (Exception $e) { $this->_db->rollBack(); Qs_Debug::processException($e); return false; } return true; } /** * @param array $tweetList RAW Tweets (twitter format) * @return array */ protected function _convertTweets($tweetList) { $result = []; $tweetList = array_reverse($tweetList); foreach ($tweetList as $tweet) { $data = (empty($tweet['retweeted_status'])) ? $tweet : $tweet['retweeted_status']; $result[] = [ 'tweetId' => $data['id_str'], 'userId' => $data['user']['id_str'], 'name' => $data['user']['name'], 'screenName' => $data['user']['screen_name'], 'imageUrl' => preg_replace('/^\w+:/', '', $data['user']['profile_image_url']), 'retwittedByName' => (empty($tweet['retweeted_status'])) ? null : $tweet['user']['name'], 'retwittedByScreenName' => (empty($tweet['retweeted_status'])) ? null : $tweet['user']['screen_name'], 'createdAt' => date('Y-m-d H:i:s', strtotime($data['created_at'])), 'text' => $data['text'], 'html' => empty($data['entities']) ? htmlspecialchars($data['text']) : $this->_prepareTextEntities($data['text'], $data['entities']), 'source' => $data['source'], 'raw' => $tweet, ]; } return $result; } /** * @param string $lastDate * @return bool|null|string */ protected function _getTimeAgo($lastDate) { $lastDate = new DateTime($lastDate); $date = new DateTime(); if ($date->getTimestamp() - $lastDate->getTimestamp() > 86400) { // more that 24h ago $result = $lastDate->format('M d'); } else { $diff = $lastDate->diff($date); $parts = 0; $ranges = ['d' => 'day', 'h' => 'hour', 'i' => 'minute']; $result = ''; foreach ($ranges as $idx => $name) { if ($diff->{$idx}) { $result .= ' ' . $diff->{$idx} . ' ' . $name . ($diff->{$idx} > 1 ? 's' : ''); if (++$parts > 2) { break; } } } if ('' == $result) { $result = 'moment ago'; } else { $result = 'about ' . ltrim($result) . ' ago'; } } return $result; } /** * Replaces tweets entities in text * * @param string $text Tweet plain text * @param array $entities @see https://dev.twitter.com/docs/tweet-entities * @return string HTML code */ protected function _prepareTextEntities($text, array $entities) { $replacements = []; foreach ($entities as $area => $items) { $pattern = $params = null; switch ($area) { case 'hashtags': $pattern = '#%s'; $params = ['text']; break; case 'user_mentions': $pattern = '@%s'; $params = ['screen_name', 'screen_name']; break; case 'media': case 'urls': $pattern = '%s'; $params = ['expanded_url', 'display_url']; break; default: break; } foreach ($items as $item) { $values = []; foreach ($params as $name) { $values[] = htmlspecialchars($item[$name]); } $replacements[] = [ 'indices' => [$item['indices'][0], $item['indices'][1]], 'pattern' => $pattern, 'params' => $values ]; } } usort( $replacements, function ($a, $b) { $a = $a['indices'][0]; $b = $b['indices'][0]; if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; } ); $result = ''; $index = 0; foreach ($replacements as $info) { $indices = $info['indices']; $result .= mb_substr($text, $index, $indices[0] - $index); $result .= vsprintf($info['pattern'], $info['params']); $index = $indices[1]; } $result .= mb_substr($text, $index, mb_strlen($text) - $index); return $result; } }