LoginSignup
7

More than 5 years have passed since last update.

posted at

updated at

Organization

BEAR.Sunday で Twitter OAuth

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に移行しないと(*´ڡ`●)

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
What you can do with signing up
7