Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Return BC, fix command, fix fetch algorithm.

  • Loading branch information...
commit 3c34f9ed636505fc695eb508bdcad6b5d7a91662 1 parent 8e66a8c
@cursedcoder cursedcoder authored stloyd committed
View
11 Command/ForceFetchLastTweetsCommand.php 100755 → 100644
@@ -27,19 +27,17 @@ protected function configure()
{
$this
->setDefinition(array(
- new InputArgument('usernames', InputArgument::REQUIRED, 'Twitter usernames'),
+ new InputArgument('username', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Twitter usernames'),
new InputOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Max number of tweets', 10),
))
- ->setDescription('Fetch the last tweets a bundle, use comma delimiter for few usernames.')
+ ->setDescription('Fetch the last tweets a bundle.')
->setHelp(<<<EOT
The <info>knp-last-tweets:force-fetch</info> command fetches the last tweets of a users.
It is useful to force the caching via a cron job rather than letting a visitor request do it.
-If you need to pass more than 1 usernames, just use comma delimiter.
-
<info>php app/console knp-last-tweets:force-fetch knplabs</info>
-<info>php app/console knp-last-tweets:force-fetch knplabs,knplabsru</info>
+<info>php app/console knp-last-tweets:force-fetch knplabs knplabsru knpuniversity</info>
EOT
)
->setName('knp-last-tweets:force-fetch')
@@ -62,7 +60,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
return;
}
- $usernames = explode(',', $input->getArgument('usernames'));
+ $usernames = $input->getArgument('username');
+
$limit = $input->getOption('limit');
$output->writeln('Fetching the <info>'.$limit.'</info> last tweets of <info>' . implode(', ', $usernames) . '</info>');
View
4 Controller/TwitterController.php 100755 → 100644
@@ -8,7 +8,7 @@
class TwitterController extends Controller
{
- public function lastTweetsAction($usernames, $limit = 10, $age = null)
+ public function lastTweetsAction($username, $limit = 10, $age = null)
{
$twitter = $this->get('knp_last_tweets.last_tweets_fetcher');
@@ -19,7 +19,7 @@ public function lastTweetsAction($usernames, $limit = 10, $age = null)
}
$response = $this->render('KnpLastTweetsBundle:Tweet:lastTweets.html.twig', array(
- 'usernames' => $usernames,
+ 'usernames' => $username,
'tweets' => $tweets,
));
View
24 README.markdown 100755 → 100644
@@ -10,13 +10,13 @@ Note that tweets are transformed so that links are clickable.
After installing the bundle, just do:
```jinja
-{% render "KnpLastTweetsBundle:Twitter:lastTweets" with {'usernames': 'knplabs'} %}
+{% render "KnpLastTweetsBundle:Twitter:lastTweets" with {'username': 'knplabs'} %}
```
Or if you want use combined feed:
```jinja
-{% render "KnpLastTweetsBundle:Twitter:lastTweets" with {'usernames': ['knplabs', 'knplabsru']} %}
+{% render "KnpLastTweetsBundle:Twitter:lastTweets" with {'username': ['knplabs', 'knplabsru']} %}
```
In that case tweets will be sorted by date.
@@ -54,6 +54,26 @@ public function registerBundles()
)
```
+Buzz is required to install for using this bundle.
+
+You should configure it in config.yml by adding
+
+```jinja
+# app/config.yml
+services:
+ buzz.message_factory:
+ class: Buzz\Message\Factory
+ public: false
+
+ buzz.client:
+ class: Buzz\Client\Curl
+ public: false
+
+ buzz:
+ class: Buzz\Browser
+ arguments: ["@buzz.client", "@buzz.message_factory"]
+```
+
## Configuration
You will now have to configure the bundle to use one of the three available drivers.
View
2  Resources/config/fetcher_driver/api.yml
@@ -4,3 +4,5 @@ parameters:
services:
knp_last_tweets.last_tweets_fetcher.api:
class: %knp_last_tweets.last_tweets_fetcher.api.class%
+ arguments:
+ - "@buzz"
View
44 Tests/Twitter/LastTweetsFetcher/ApiFetcherTest.php 100755 → 100644
@@ -13,7 +13,11 @@ public function testMultiAccountFetch()
{
$mockedTweet = $this->getMockedTweet();
- $fixture = json_encode(array('one', 'two', 'three'));
+ $fixture = json_encode(array(
+ 'one' => array('id_str' => 1, 'text' => 'asdasdasd'),
+ 'two' => array('id_str' => 2, 'text' => 'asdasdasd2'),
+ 'three' => array('id_str' => 3, 'text' => 'asdasdasd3')
+ ));
$fetcher = $this->getMockedFetcher($fixture, 3);
@@ -46,7 +50,10 @@ public function testFetchReturnsTweets()
$mockedTweet = $this->getMockedTweet();
// Mock the fetcher
- $fixture = json_encode(array('one', 'two'));
+ $fixture = json_encode(array(
+ 'one' => array('id_str' => 1, 'text' => 'asdasdasd'),
+ 'two' => array('id_str' => 2, 'text' => 'asdasdasd2')
+ ));
$fetcher = $this->getMockedFetcher($fixture);
@@ -63,7 +70,12 @@ public function testFetchReturnsLimit()
{
$mockedTweet = $this->getMockedTweet();
- $fixture = json_encode(array('one', 'two', 'three', 'four'));
+ $fixture = json_encode(array(
+ 'one' => array('id_str' => 1, 'text' => 'asdasdasd'),
+ 'two' => array('id_str' => 2, 'text' => 'asdasdasd2'),
+ 'three' => array('id_str' => 3, 'text' => 'asdasdasd3'),
+ 'four' => array('id_str' => 4, 'text' => 'asdasdasd4')
+ ));
$fetcher = $this->getMockedFetcher($fixture, 3);
@@ -83,12 +95,13 @@ public function testUnableToFetchData()
{
$fetcher = $this->getMock(
self::CLASSNAME,
- array('getContents', 'createTweet')
+ array('getContents', 'createTweet'),
+ array($this->getMockedBrowser())
);
$fetcher->expects($this->once())
->method('getContents')
- ->with($this->equalTo('http://api.twitter.com/1/statuses/user_timeline.json?screen_name=knplabs&count=10&trim_user=1&exclude_replies=true'))
+ ->with($this->stringContains('http://api.twitter.com/1/statuses/user_timeline.json'))
->will($this->returnValue(null));
$tweets = $fetcher->fetch('knplabs');
@@ -101,12 +114,13 @@ public function testFetchBadData()
{
$fetcher = $this->getMock(
self::CLASSNAME,
- array('getContents', 'createTweet')
+ array('getContents', 'createTweet'),
+ array($this->getMockedBrowser())
);
$fetcher->expects($this->once())
->method('getContents')
- ->with($this->equalTo('http://api.twitter.com/1/statuses/user_timeline.json?screen_name=knplabs&count=10&trim_user=1&exclude_replies=true'))
+ ->with($this->stringContains('http://api.twitter.com/1/statuses/user_timeline.json'))
->will($this->returnValue('a{'));
$tweets = $fetcher->fetch('knplabs');
@@ -121,18 +135,22 @@ protected function getMockedFetcher($fixture, $count = 10)
{
$fetcher = $this->getMock(
self::CLASSNAME,
- array('getContents', 'createTweet')
+ array('getContents', 'createTweet'),
+ array($this->getMockedBrowser())
);
$fetcher->expects($this->atLeastOnce())
->method('getContents')
- ->with($this->logicalOr(
- $this->equalTo(sprintf('http://api.twitter.com/1/statuses/user_timeline.json?screen_name=knplabs&count=%d&trim_user=1&exclude_replies=true', $count)),
- $this->equalTo(sprintf('http://api.twitter.com/1/statuses/user_timeline.json?screen_name=knplabsru&count=%d&trim_user=1&exclude_replies=true', $count))
- ))
+ ->with($this->stringContains('http://api.twitter.com/1/statuses/user_timeline.json'))
->will($this->returnValue($fixture));
return $fetcher;
}
-
+
+ protected function getMockedBrowser()
+ {
+ $browser = $this->getMock('Buzz\Browser');
+
+ return $browser;
+ }
}
View
87 Twitter/LastTweetsFetcher/ApiFetcher.php 100755 → 100644
@@ -4,55 +4,65 @@
use Knp\Bundle\LastTweetsBundle\Twitter\Exception\TwitterException;
use Knp\Bundle\LastTweetsBundle\Twitter\Tweet;
+use Buzz\Browser;
class ApiFetcher implements FetcherInterface
{
protected $browser;
- public function __construct()
+ public function __construct($browser)
{
- $this->browser = new \Buzz\Browser;
+ $this->browser = $browser;
}
- public function fetch($usernames, $limit = 10)
+ public function fetch($usernames, $count = 10, $excludeReplies = true, $includeRts = false, $retryCall = 1)
{
- if(!is_array($usernames)) {
+ if (!is_array($usernames)) {
$usernames = array((string) $usernames);
}
+ $maxId = 0;
+ $page = 1;
+ $limit = $count;
+ $count *= 2; // in order to decrease api requests
$combineData = array();
- foreach ($usernames as $username) {
- $url = sprintf('http://api.twitter.com/1/statuses/user_timeline.json?screen_name=%s&count=%d&trim_user=1&exclude_replies=true', $username, $limit);
- $data = $this->getContents($url);
-
- if (empty($data)) {
- throw new TwitterException('Received empty data from api.twitter.com');
+ for ($i = 0; $i < $page && ($page - 1) <= $retryCall; $i++) {
+ foreach ($usernames as $username) {
+ $queryString = sprintf('?screen_name=%s&count=%d&trim_user=1&exclude_replies=%d&include_rts=%d&page=%d', urlencode($username), $count, $excludeReplies, $includeRts, $page);
+
+ $url = 'http://api.twitter.com/1/statuses/user_timeline.json' . $queryString;
+
+ if($maxId) {
+ $url .= sprintf("&max_id=%d", $maxId);
+ }
+
+ $data = $this->fetchTweets($url);
+
+ // we need to inject username, when use "trim_user"
+ array_walk($data, function(&$tweet) use($username) {
+ if (is_array($tweet)) {
+ $tweet['username'] = $username;
+ }
+ });
+
+ $combineData = array_merge($combineData, $data);
}
- $data = json_decode($data, true);
-
- if (null === $data) {
- throw new TwitterException('Unable to decode data from api.twitter.com');
+ if (count($combineData) < $limit) {
+ $maxId = end($combineData);
+ $maxId = $maxId['id_str'];
+
+ $page++;
+ } else {
+ usort($combineData, function($a, $b) {
+ return ($a['id_str'] > $b['id_str']) ? -1 : 1;
+ });
+
+ $combineData = array_slice($combineData, null, $limit);
}
-
- // we need to inject username, when use "trim_user"
- array_walk($data, function(&$tweet) use($username) {
- if (is_array($tweet)) {
- $tweet['username'] = $username;
- }
- });
-
- $combineData = array_merge($combineData, $data);
}
- usort($combineData, function($a, $b) {
- return ($a['id'] > $b['id']) ? -1 : 1;
- });
-
- $combineData = array_slice($combineData, null, $limit);
-
- $i = 0;
$tweets = array();
foreach ($combineData as $tweetData) {
@@ -61,7 +71,24 @@ public function fetch($usernames, $limit = 10)
return $tweets;
}
+
+ protected function fetchTweets($url)
+ {
+ $data = $this->getContents($url);
+
+ if (empty($data)) {
+ throw new TwitterException('Received empty data from api.twitter.com');
+ }
+ $data = json_decode($data, true);
+
+ if (null === $data) {
+ throw new TwitterException('Unable to decode data from api.twitter.com');
+ }
+
+ return $data;
+ }
+
protected function getContents($url)
{
return $this->browser->get($url)->getContent();
View
14 Twitter/Tweet.php 100755 → 100644
@@ -8,6 +8,8 @@ class Tweet
protected $createdAt;
protected $text;
protected $username;
+ protected $isReply;
+ protected $isRts;
public function __construct(array $object)
{
@@ -15,6 +17,8 @@ public function __construct(array $object)
$this->createdAt = new \DateTime($object['created_at']);
$this->text = $object['text'];
$this->username = $object['username'];
+ $this->isReply = (bool) $object['in_reply_to_screen_name'];
+ $this->isRts = (bool) $object['retweeted_status'];
}
public function getText()
@@ -46,4 +50,14 @@ public function getUrl()
{
return sprintf('https://twitter.com/%s/status/%s', $this->getUsername(), $this->getId());
}
+
+ public function isReply()
+ {
+ return $this->isReply;
+ }
+
+ public function isRts()
+ {
+ return $this->isRts;
+ }
}
View
3  composer.json
@@ -19,7 +19,8 @@
"require": {
"php": ">=5.3.2",
- "symfony/framework-bundle": ">=2.0.0"
+ "symfony/framework-bundle": ">=2.0.0",
+ "kriswallsmith/buzz": ">=v0.5"
},
"recommend": {
Please sign in to comment.
Something went wrong with that request. Please try again.