7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

BEAR.SundayAdvent Calendar 2014

Day 23

BEAR.Sunday で Twitter OAuth

Last updated at Posted at 2014-12-22

2015/01/08追記 ココカラ-->

本エントリ内で紹介している src/Module/OAuth/Twitter{Module|Provider}.php は外部モジュールとして切り出し、 ray/oauth-module として公開しています。

<--ココマデ


つい昨日(2014/12/22)、BEAR.Sunday v1.0.0-alpha がリリースされました!

最初に

今ちょうどプライベートでBEAR.Sundayを使ったサービス開発を進めていて、TwitterへのOAuthという大きめの実装に着手しようとしていたので、この機会にAdventCalendarのエントリとして実装例を紹介します。

BEAR.Sunday と PHPoAuthLib

  • BEAR.Sunday

    • リソース指向のPHPフレームワーク
    • DIとAOPをサポート
    • BEAR.PackageBEAR.ResourceBEAR.Sundayの3つのパッケージから構成される
    • 2014/12/22にv1.0.0-alphaリリースされましたが、自分のプロジェクトで使用しているバージョンがv0.10.5のため、本エントリではv0.10系を使用する前提で書いています
  • PHPoAuthLib

    • PHP製のOAuthライブラリ
    • Twitter以外にも多くのサービスをサポートしている
    • いくつか存在するPHPのOAuthライブラリの中で1番オブジェクト指向でしっかり設計されている(と思う(小並感))

本エントリで詳しく説明しないこと

  • BEAR.Sunday(v0.10系)のプロジェクト作成方法

     $ composer create-project bear/skeleton:~0.10 My.Project
     $ cd My.Project
     $ composer install
    
  • BEAR.SundayのDI(Dependency Injection)の仕組み
  • OAuthの仕組み
  • Twitterアプリの作成方法(=APIキーの取得方法)

Twitterアプリの設定

Twitterアプリの管理ページWebsiteCallback URL を設定します。

Pentan_Local___Twitter_Application_Management.png

プロジェクト構成

編集/追加した部分以外は、基本的にComposerコマンドで作成したそのままのプロジェクト構成です。

TwitterProvider_php_-pentan-pentan-___workspace_pentan.png

PHPoAuthLibのインストール

src/composer.json (編集)

	"require": {
		"php": "5.5.*",
		"bear/package": "0.13.0",
+		"lusitanian/oauth": "~0.3",
		"ext-apcu": "*",
		"ext-mbstring": "*"
	},

TwitterのAPIキーを定数として定義し、DIにより使用する

var/conf/constants.php (編集)

Twitter APIのConsumer Key,Consumer SecretCallback URLを定数として定義し、以降のロジックからDIの仕組みにより使用します。

	'prod' => [
		// DB
		'master_db' => $masterDb,
		'slave_db'  => $slaveDb,
+		// Twitter API
+		'twitter_api' => [
+			'consumer_key'    => '{YOUR_CONSUMER_KEY}',
+			'consumer_secret' => '{YOUR_CONSUMER_SECRET}',
+			// OAuth時のコールバックURLパス
+			'oauth_callback_path' => '/oauth/twitter/callback',
+		],
	],

PHPoAuthLibをDIする

src/Module/OAuth/TwitterProvider.php (追加)

PHPoAuthLibをBEAR.SundayのDIの仕組みから使うための初期化処理を記述します。

<?php

namespace My\Project\Module\OAuth;

use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Uri\UriFactory;
use OAuth\Common\Storage\Session;
use OAuth\OAuth1\Service\Twitter;
use OAuth\ServiceFactory;
use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;
use Ray\Di\ProviderInterface;

class TwitterProvider implements ProviderInterface
{
	/**
	 * @var string
	 */
	private $consumerKey;

	/**
	 * @var string
	 */
	private $consumerSecret;

	/**
	 * @var string
	 */
	private $oauthCallbackPath;

	/**
	 * @param array $apiConfig
	 *
	 * @Inject
	 * @Named("twitter_api")
	 */
	public function __construct($apiConfig)
	{
		$this->consumerKey    = $apiConfig['consumer_key'];
		$this->consumerSecret = $apiConfig['consumer_secret'];
		$this->oauthCallbackPath = $apiConfig['oauth_callback_path'];
	}

	/**
	 * @return \OAuth\OAuth1\Service\Twitter
	 */
	public function get()
	{
		// コールバックURLの生成
		$uri = (new UriFactory())->createFromSuperGlobalArray($_SERVER);
		$uri->setPath($this->oauthCallbackPath);
		$uri->setQuery('');
		$callbackUrl = $uri->getAbsoluteUri();

		$credentials = new Credentials(
			$this->consumerKey,
			$this->consumerSecret,
			$callbackUrl
		);

		// Twitter用のOAuthサービスインスタンスを生成
		return (new ServiceFactory())->createService('twitter', $credentials, new Session());
	}
}

src/Module/OAuth/TwitterModule.php (追加)

上で作成したTwitterProvider(のgetメソッドの戻り値)を\OAuth\OAuth1\Service\Twitterに注入(束縛)するための設定を記述します。

<?php

namespace My\Project\Module\OAuth;

use OAuth\OAuth1\Service\Twitter;
use Ray\Di\AbstractModule;
use Ray\Di\Scope;

class TwitterModule extends AbstractModule
{

	protected function configure()
	{
		$this->bind(Twitter::class)->toProvider(TwitterProvider::class)->in(Scope::SINGLETON);
	}
}

src/Module/App/Dependency.php (編集)

    protected function configure()
    {
+		$this->install(new TwitterModule());
    }

src/Module/AppModule.php (編集)

依存をアプリにインストールします。

	protected function configure()
	{
		$this->install(new StandardPackageModule('Kawanamiyuu\Pentan', $this->context, dirname(dirname(__DIR__))));
		
		// override module
		// $this->install(new SmartyModule($this));
		
		// $this->install(new AuraViewModule($this));
		
		// install application dependency
-		// $this->install(new App\Dependency);
+		$this->install(new App\Dependency);
		
		// install application aspect
		 $this->install(new App\Aspect($this));
	}
}

src/Inject/TwitterOAuthServiceInject.php (追加)

プログラムからはこのtraitをuseすることでOAuthロジックを使用します。setTwitterOAuthServiceで依存が注入されます。

<?php

namespace My\Project\Inject;


use OAuth\OAuth1\Service\Twitter;
use Ray\Di\Di\Inject;

trait TwitterOAuthServiceInject
{
	/**
	 * @var Twitter
	 */
	protected $twitterOAuthService;

	/**
	 * @param Twitter $twitter
	 *
	 * @Inject
	 */
	public function setTwitterOAuthService(Twitter $twitter)
	{
		$this->twitterOAuthService = $twitter;
	}
} 

Twitterの認証画面へのリダイレクト

src/Resource/Page/Oauth/Twitter/Redirect.php (追加)

Twitterの認証画面 にリダイレクトする ためのPageリソースです。
次のURLパスに対応します→ /oauth/twitter/redirect

<?php

namespace My\Project\Resource\Page\Oauth\Twitter;

use BEAR\Resource\ResourceObject;
use My\Project\Inject\TwitterOAuthServiceInject;

class Redirect extends ResourceObject
{
	use TwitterOAuthServiceInject;

	public function onGet()
	{
		// リクエストトークンを取得
		$requestToken = $this->twitterOAuthService->requestRequestToken()->getRequestToken();

		$url = $this->twitterOAuthService->getAuthorizationUri([
			'oauth_token' => $requestToken,
			'force_login' => 'true',
		]);

		// Twitterの認証画面へリダイレクト
		header('Location:' . $url);
		exit;
	}
} 

Twitterの認証画面からのコールバック

src/Resource/Page/Oauth/Twitter/Callback.php (追加)

Twitterの認証画面 からリダイレクトされる Pageリソースです。
次のURLパスに対応します→ /oauth/twitter/callback

<?php

namespace My\Project\Resource\Page\Oauth\Twitter;

use BEAR\Resource\ResourceObject;
use My\Project\Inject\TwitterOAuthServiceInject;

class Callback extends ResourceObject
{
	use TwitterOAuthServiceInject;

        /**
         * @param string $oauth_token
         * @param string $oauth_verifier
         * @param string $denied
         */
	public function onGet($oauth_token = null, $oauth_verifier = null, $denied = null)
	{
		// Twitterの認証画面で[キャンセル]ボタンを押された場合
		if ($denied) {
			$this['is_authorized'] = false;
			return $this;
		}

		// アクセストークンを取得
		$accessToken = $this->twitterOAuthService->requestAccessToken(
			$oauth_token,
			$oauth_verifier
		);

		// 認証成功時
		$this['is_authorized'] = true;
		$this['token']         = $accessToken->getAccessToken();
		$this['token_secret']  = $accessToken->getAccessTokenSecret();
		$this['user_id']       = $accessToken->getExtraParams()['user_id'];
		$this['screen_name']   = $accessToken->getExtraParams()['screen_name'];
		return $this;
	}
} 

src/Resource/Page/Oauth/Twitter/Callback.twig (追加)

※注意※
ここではサンプルコードとしての便宜上、取得したトークンを画面に表示します。プロダクションコードではDBに保存後リダイレクトするなどして適切にハンドリングします。

<html lang="ja">
<head>
<meta charset="utf-8" />
<style type="text/css">
	dt { font-weight: bold; }
	dt:after { content: ':'; }
</style>
</head>
<body>
{% if is_authorized %}
	<dl>
		<dt>Token</dt><dd>{{ token }}</dd>
		<dt>Token Secret</dt><dd>{{ token_secret }}</dd>
	</dl>
	<dl>
		<dt>user_id</dt><dd>{{ user_id }}</dd>
		<dt>screen_name</dt><dd>{{ screen_name }}</dd>
	</dl>
{% else %}
	<p>
		<a href="/oauth/twitter/redirect">リトライ</a>
	</p>
{% endif %}
</body>
</html>

ローカルでの動作確認

1. ビルドインサーバを起動する

$ cd /path/to/My.Project
# DI、AOPのためのコンパイルキャシュを削除
$ php bin/clear.php
$ php -S localhost:8080 -t var/www

2. http://localhost:8080/oauth/twitter/redirect にアクセスする

3. Twitterの認証画面にリダイレクトされる

Twitter___アプリケーション認証 2.png

4. [連携アプリを認証]ボタンを押す

5. http://localhost:8080/oauth/twitter/callback にリダイレクトされる

アクセストークンが表示されればOK

Twitter___アプリケーション認証.png

最後に

今回作成したコードの大半がDIの仕組みに関する部分であったように、BEAR.Sundayを使った開発ではDIが実装の肝になってきます。
自分も今回初めて本格的に外部ライブラリをDIして使用するコードを書いてみてその仕組みの理解が進みました。

今後もBEAR.Sundayを使った開発を通してその設計思想を学んでいきたいと思います。
とりあえず次は今のプロジェクトのコードベースをv1.0.0-alphaに移行しないと(*´ڡ`●)

7
7
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?