Bu örnek API şeklinde dizayn edilmiş bir symfony uygulaması üzerinden çalışmaktadır, bu nedenle daha önceden yazılmış olan yazıları okursanız iyi olur.


Composer update


Gerekli olan "abraham/twitteroauth" : "0.5.3" paketini composer ile yükleyin. Paket hakkında daha fazla bilgi için anasayfa ve GitHub sayfalarını okuyun.


Twitter OAuth bilgileri


Bu örnekte kendi OAuth bilgilerinize ihtiyacınız olacak, bu nedenle aşağıdaki adımları takip edin.



Parameters.yml


Tweet yaratırken resimde göndereceğiz, bu nedenle örnek resimlerimizin yolunu belirtelim.


parameters:
twitter.image.directory: '%kernel.root_dir%/../build/dummy/image/'

#football/build/dummy/image/png.png
#football/build/dummy/image/jpg.jpg

Controllers.yml


services:
application_backend.controller.abstract:
class: Application\BackendBundle\Controller\AbstractController
abstract: true # Abstract enabled
arguments:
- @serializer # Enabled by JMS Serializer Bundle
- @validator # Enabled by the application by default
- @doctrine_common_inflector # Enabled by user

application_backend.controller.twitter:
class: Application\BackendBundle\Controller\TwitterController
parent: application_backend.controller.abstract # Parent abstract class
arguments:
- @application_backend.service.twitter # Twitter service

# Application level services
doctrine_common_inflector:
class: Doctrine\Common\Inflector\Inflector

Services.yml


services:
application_backend.service.twitter:
class: Application\BackendBundle\Service\TwitterService
arguments:
- @application_backend.util.twitter # Twitter utility class
- @application_backend.factory.twitter # Twitter factory class

application_backend.util.twitter:
class: Application\BackendBundle\Util\TwitterApi
arguments:
- %twitter.image.directory% # Where tweet images stored

Factories.yml


services:
application_backend.factory.twitter:
class: Application\BackendBundle\Factory\TwitterFactory

AbstractController.php


namespace Application\BackendBundle\Controller;

use Doctrine\Common\Inflector\Inflector;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

abstract class AbstractController
{
protected $serializer;
protected $validator;
protected $inflector;

public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->inflector = $inflector;
}

/**
* @param string $responseData
* @param int $status
*
* @return Response
*/
protected function createJsonResponse($responseData = '', $status = 200)
{
$context = new SerializationContext();
$context->setSerializeNull(false);

$jsonResponse = $this->serializer->serialize($responseData, 'json', $context);

return (new Response(
$jsonResponse,
$status,
['Content-Type' => 'application/json']
));
}

/**
* @param $errors
* @param int $status
*
* @return Response
*/
protected function createJsonErrorResponse($errors, $status = 400)
{
$errorData = ['errors' => []];

foreach ($errors as $error) {
if ($error instanceof ConstraintViolationInterface) {
$preparedError = $this->getErrorFromValidation($error, $errorData);
} else {
$preparedError = ['key' => count($errorData['errors']), 'value' => $error];
}
$errorData['errors'][$preparedError['key']] = $preparedError['value'];
}

return $this->createJsonResponse($errorData, $status);
}

/**
* @param string $content
* @param string $class
*
* @return mixed|Response
*/
protected function validate($content, $class)
{
$content = $this->serializer->deserialize(
$content,
$class,
'json'
);

$errors = $this->validator->validate($content);
if (count($errors)) {
return $this->createJsonErrorResponse($errors);
}

return $content;
}

/**
* @param ConstraintViolationInterface $error
*
* @return mixed
*/
private function getErrorFromValidation($error)
{
$properties = $this->inflector->tableize($error->getPropertyPath());

return ['key' => $properties, 'value' => $error->getMessage()];
}
}

TwitterController.php


namespace Application\BackendBundle\Controller;

use Application\BackendBundle\Exception\TwitterException;
use Application\BackendBundle\Service\TwitterServiceInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\Common\Inflector\Inflector;
use Exception;

/**
* @Route("twitter", service="application_backend.controller.twitter")
*/
class TwitterController extends AbstractController
{
private $twitterService;

public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector,
TwitterServiceInterface $twitterService
) {
parent::__construct($serializer, $validator, $inflector);

$this->twitterService = $twitterService;
}

/**
* @param Request $request
*
* @Route("")
* @Method({"GET"})
*
* @return Response
* @throws TwitterException
*/
public function listAction(Request $request)
{
try {
$tweets = $this->twitterService->getTweets(
$request->query->get('screen_name'),
$request->query->get('count', 25),
$request->query->get('exclude_replies', true),
$request->query->get('since_id', null),
$request->query->get('max_id', null)
);
} catch (Exception $e) {
throw new TwitterException($e->getMessage());
}

return $this->createJsonResponse($tweets);
}

/**
* @param Request $request
*
* @Method({"POST"})
* @Route("")
*
* @return Response
*/
public function createTweetAction(Request $request)
{
$tweet = $this->validate(
$request->getContent(),
'Application\BackendBundle\Model\Twitter\NewTweet'
);
if ($tweet instanceof Response) {
return $tweet;
}

try {
$response = $this->twitterService->createTweet($tweet);
} catch (Exception $e) {
throw new TwitterException($e->getMessage());
}

return $this->createJsonResponse($response);
}
}

TwitterServiceInterface.php


namespace Application\BackendBundle\Service;

use Application\BackendBundle\Model\Twitter\Error;
use Application\BackendBundle\Model\Twitter\NewTweet;

interface TwitterServiceInterface
{
/**
* @param string $screenName
* @param int $count
* @param bool $excludeReplies
* @param int|null $sinceId
* @param int|null $maxId
*
* @return mixed
*/
public function getTweets(
$screenName,
$count = 25,
$excludeReplies = true,
$sinceId = null,
$maxId = null
);

/**
* @param NewTweet $newTweet
*
* @return bool|Error
*/
public function createTweet(NewTweet $newTweet);
}

TwitterService.php


namespace Application\BackendBundle\Service;

use Application\BackendBundle\Factory\TwitterFactoryInterface;
use Application\BackendBundle\Model\Twitter\NewTweet;
use Application\BackendBundle\Util\TwitterApi;

class TwitterService implements TwitterServiceInterface
{
private $twitterApi;
private $twitterFactory;

public function __construct(
TwitterApi $twitterApi,
TwitterFactoryInterface $twitterFactory
) {
$this->twitterApi = $twitterApi;
$this->twitterFactory = $twitterFactory;
}

public function getTweets(
$screenName,
$count = 25,
$excludeReplies = true,
$sinceId = null,
$maxId = null
) {
$payload['screen_name'] = $screenName;
$payload['count'] = $count;
$payload['exclude_replies'] = $excludeReplies;
if (!is_null($sinceId)) {
$payload['since_id'] = $sinceId;
}
if (!is_null($maxId)) {
$payload['max_id'] = $maxId;
}

$tweets = $this->twitterApi->getTweets($payload);

return $this->twitterFactory->createTweetList($tweets);
}

public function createTweet(NewTweet $newTweet)
{
$result = $this->twitterApi->createTweet($newTweet);

if ($result->errors) {
return $this->twitterFactory->createError($result->errors);
}

return;
}
}

TwitterApi.php


namespace Application\BackendBundle\Util;

use Abraham\TwitterOAuth\TwitterOAuth;
use Application\BackendBundle\Model\Twitter\NewTweet;

/**
* Example below uses our own Twitter account.
* To post a tweet to someone elses or multiple accounts, we need associated oAuth Tokens to those accounts.
*/
class TwitterApi
{
const API_DOMAIN = 'https://api.twitter.com/1.1/';
const CONSUMER_KEY = '8TcNEf477DHV***************';
const CONSUMER_SECRET = 'sw0QwysUZRBFPVOdHIhzWNsvL**************';
const ACCESS_TOKEN = '3159342661-1oNWsZmekO36mJKWKP**************';
const ACCESS_SECRET_TOKEN = 'aJcV4JgxPRzGVKL7PLZcrtsF**************';

private $twitterImageDirectory;
private $connection;

public function __construct($twitterImageDirectory)
{
$this->twitterImageDirectory = $twitterImageDirectory;
$this->connection = new TwitterOAuth(
self::CONSUMER_KEY,
self::CONSUMER_SECRET,
self::ACCESS_TOKEN,
self::ACCESS_SECRET_TOKEN
);
}

public function getTweets(array $payload)
{
return $this->connection->get('statuses/user_timeline', $payload);
}

public function createTweet(NewTweet $newTweet)
{
$parameters['status'] = $newTweet->text;

if ((bool) $newTweet->images) {
$parameters['media_ids'] = $this->uploadImages($newTweet->images);
}

return $this->connection->post("statuses/update", $parameters);
}

/**
* @param array $images
*
* @return string
*/
private function uploadImages(array $images)
{
$mediaIds = null;

foreach ($images as $image) {
if (file_exists($this->twitterImageDirectory.$image)) {
$upload = $this->connection->upload(
'media/upload',
['media' => $this->twitterImageDirectory.$image]
);
$mediaIds .= $upload->media_id_string.',';
}
}

return substr($mediaIds, 0, -1);
}
}

TwitterFactoryInterface.php


namespace Application\BackendBundle\Factory;

use Application\BackendBundle\Model\Twitter\Error;
use Application\BackendBundle\Model\Twitter\TweetList;

interface TwitterFactoryInterface
{
/**
* @param array $tweets
*
* @return TweetList
*/
public function createTweetList(array $tweets);

/**
* @param array $errors
*
* @return Error
*/
public function createError(array $errors);
}

TwitterFactory.php


namespace Application\BackendBundle\Factory;

use Application\BackendBundle\Model\Twitter\Error;
use Application\BackendBundle\Model\Twitter\Tweet;
use Application\BackendBundle\Model\Twitter\TweetList;
use stdClass;

class TwitterFactory implements TwitterFactoryInterface
{
public function createTweetList(array $tweets)
{
$tweetList = new TweetList();
foreach ($tweets as $tweet) {
$tweetList->tweets[] = $this->getTweet($tweet);
}

return $tweetList;
}

public function createError(array $errors)
{
$errorList = new Error();

foreach ($errors as $error) {
$errorList->errors[] = [
'code' => $error->code,
'message' => $error->message,
];
}

return $errorList;
}

/**
* @param stdClass $tweetData
*
* @return Tweet
*/
private function getTweet(stdClass $tweetData)
{
$tweet = new Tweet();
$tweet->createdAt = date('Y-m-d H:i:s', strtotime(($tweetData->created_at)));
$tweet->id = $tweetData->id;
$tweet->text = $tweetData->text;

return $tweet;
}
}

Error.php


namespace Application\BackendBundle\Model\Twitter;

class Error
{
/**
* @var array
*/
public $errors = [];
}

NewTweet.php


namespace Application\BackendBundle\Model\Twitter;

use Symfony\Component\Validator\Constraints as Assert;
use JMS\Serializer\Annotation as Serializer;

class NewTweet
{
/**
* @var string
*
* @Assert\NotBlank(message="Tweet message is required.")
* @Assert\Length(max="140", maxMessage="Tweet cannot be longer than 140 chars in length.")
*
* @Serializer\Type("string")
*/
public $text;

/**
* @var array
*
* @Serializer\Type("array")
*/
public $images = [];
}

Tweet.php


namespace Application\BackendBundle\Model\Twitter;

use DateTime;

class Tweet
{
/**
* @var int
*/
public $id;

/**
* @var datetime
*/
public $createdAt;

/**
* @var string
*/
public $text;
}

TweetList.php


namespace Application\BackendBundle\Model\Twitter;

class TweetList
{
/**
* @var Tweet[]
*/
public $tweets = [];
}

TwitterException.php


namespace Application\BackendBundle\Exception;

use RuntimeException;

/**
* Triggered when twitter related error occurs.
*/
class TwitterException extends RuntimeException
{
}

Örnekler


Testlerde chrome postman extension kullanıldı. URI'ye daha fazla parametre ekleyebilirsiniz ama nasıl yapacağınızı Twitter API dökümantasyonundan öğrenebilirsiniz.


Tweetleri listeleme


# GET http://football.local/app_test.php/backend/twitter?screen_name=YourScreenName&count=10&exclude_replies=true

# Response
{
"tweets": [
{
"id": 614525596304056300,
"created_at": "2015-06-26 21:08:14",
"text": "Test tweet with two images http://t.co/xxxxxxxx"
},
{
"id": 589094824239898600,
"created_at": "2015-04-17 16:55:25",
"text": "Just launched! 10 available now! http://t.co/bEixxxxxxxx"
},
{
"id": 589094662381707300,
"created_at": "2015-04-17 16:54:47",
"text": "Just launched! 20 available now! http://t.co/7ZUDxxxxxx"
}
]
}

İçinde resimler olan yeni bir tweet yaratma


# POST http://football.local/app_test.php/backend/twitter

# Request payload
{
"text": "Test tweet with two images",
"images": [
"png.png",
"jpg.jpg"
]
}

# Successful response
{}

# Error response
{
"errors": [
{
"code": 44,
"message": "media_ids parameter is invalid."
}
]
}