参考資料
今回はこれをなぞります。
以前は理解できずに挫折しましたが、今なら理解できるはず……!
古い情報なのでバージョンは5.5ではないっぽいです。
前段
これで作成中のアプリに機能を追加していきます。
FacebookSDKのインストール(※)
結論からいうとこの手順は必要ありません。
composer require facebook/php-sdk
インストールはできたんですが、なんか怒られました。
Package facebook/php-sdk is abandoned, you should avoid using it. Use facebook/graph-sdk instead.
php-sdkというのはもう使われてないのでgraph-sdkを使ってねとのこと。
グラフ……?って気分になりますが本当なんでしょうか。
とりあえずそっちもインストールしておくことにします。
Facebookアプリの作成
これは済んでいるのでスルー。
ドメインとコールバックURLの指定をしっかりしましょう。
FB側の認証ってどうすればいいんだろう、ひたすらにめんどい
configファイルの作成
app/config/facebook.php
とありますが、Laravel5.5だとconfig/facebook.php
ですね。
DBの作成
これもフォルダ配置が微妙に違います。
usersはすでに作成しているので、適当に項目を変更しました。
photoを追加しただけかな。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('email')->unique();
$table->string('photo');
$table->string('name');
$table->string('password');
$table->string('lang')->default('en');
$table->string('timezone')->default('UTC');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
profilesは作成します。
あ、migrate:make
じゃなくてmake:migration
みたいです。
なんか前にもやった気がするこれ。
(ていうかLaravelのバージョンがそもそも違うのを参考にしているという……)
$ php artisan make:migration create_profiles_table
Created Migration: 2017_12_31_063451_create_profiles_table
public function up()
{
Schema::create('profiles', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('username');
$table->biginteger('uid')->unsigned();
$table->string('access_token');
$table->string('access_token_secret');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('profiles');
}
DBの作成。
$ php artisan migrate:reset
$ php artisan migrate
既存テーブルの構造を修正したので一度resetしています。
モデルの作成
モデルの場所は、デフォルトのままapp直下にしています。
微妙に宣言とか足りてなかったので参考資料に手を入れてます。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Profile Extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
public function profiles()
{
return $this->hasMany('App\Profile');
}
ルーティングの設定
app.routes.php
とありますが……これはroutes/web.php
でいいのかな。
これに追記しました。
つないでみるが……ダメ……ッ!
指定されたアプリidは無効なアプリidのようです。
とか言われてしまいました。
なんなん。
php-sdkがダメなんですかね。
そういえば以前利用した、socialiteとかいうやつならログインできています。
これ流用できたりするのかな?
今回のはroutes/web.php
に処理が記載されています。
Socialiteはapp/Http/Controllers/Auth/SocialController.php
というところで処理を記述していました。
ちょっと処理を見比べてみます。
ログイン部分
だいぶ処理の趣が異なってました。
が、やってることは変わらなくて、Socialiteを使えば1行でできるというくらいの差しかありませんでした。
よってスルー。
コールバック部分
どちらも戻り値的なところなのかfacebookのAPIなのかよくわかりませんが何らかの値を取得していました。
利用するパラメータは以下の通り。
- 今回のやつ
- user
- uid
- name(first_name + last_name)
- username
- profile
- uid
- username
- access_token
- access_token_secret
- user
- Socialiteのやつ
- token
- refreshToken
- expiresIn
- id
- nickname
- name
- avatar
- user
- name
- gender
- verified
- link
- id
- avatar_original
- profileUrl
(ここでQiitaメンテが発生して泣いてました。Kobitoはこういうときに必要なのかもしれません)
修正案
方針としてはSocialController.phpのコールバック処理を書き換えることにします。
これに伴い、参照関係をいろいろと追加。
完成したのがこちら。
ここでこんなに処理書いちゃっていいのだろうかという一抹の不安がありますが無視します。
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Socialite;
use DB;
use Auth;
use Redirect;
use App\User;
use App\Profile;
class SocialController extends Controller
{
public function viewLogin()
{
return view('auth.login');
}
public function redirectToFacebookProvider()
{
return Socialite::driver('facebook')->redirect();
}
public function handleFacebookProviderCallback()
{
try{
DB::transaction(function () {
$me = Socialite::driver('facebook')->user();
if($me){
$uid = $me->getId();
$profile = Profile::whereUid($uid)->first();
if (empty($profile)) {
$user = new User;
$user->name = $me->getName();
$user->email = $me->getEmail();
$user->photo = $me->getAvatar();
$user->password = "hogehoge";
$user->save();
$profile = new Profile();
$profile->uid = $uid;
$profile->username = $me->getName();
$profile->access_token = "fuga";
$profile->access_token_secret = "hoge";
$profile = $user->profiles()->save($profile);
}
$profile->access_token = "hoge";
$profile->access_token_secret = "fuga";
//$profile->access_token = $facebook->getAccessToken();
$profile->save();
$user = $profile->user;
Auth::login($user);
// dd($user);
dd($profile);
}
});
return Redirect::to('/')->with('message', 'Facebookログインしました');
}catch(Exception $e){
return redirect("/");
}
}
}
アクセストークンとかなんか無視しちゃいけなさげなパラメータがちらほらと見えますが、とりあえず無視します。
できました(真顔)
試行錯誤部分
トランザクション
デバッグの最中に、usersだけに値が入ってprofilesに入っていない状態が発生しました。
profilesで存在確認を行うので、このままだとINSERTしようとしてしまい、キー重複でエラーになります。
正しく動けば発生しない状態ではあるものの、後のことも考えるとトランザクションの方法は調べておいて損はなさそうです。
というわけで、これを見ながらDB::transaction(function (){〜〜〜});
を追加してます(反映済み)。
最初はsave()の前後だけでいいかと思ってたんですが、中が無名関数になるため変数的にいろいろ面倒になり、try全体を含めました。
リターンでリダイレクト返すの違う……?
なんかcallbackからページ遷移しませんでした。
と思ったら、リターンをトランザクションの中に入れてたのが動かない原因のようでした。
そりゃ動きませんて。
ついでにログインボタンを出したい
作ってるサービスの都合上、FBログインを必須にしたいので、本来のログインページを潰します。
というわけでルーティングをいじって、my.blade.php
あたりでメニューのログインを変更したり、ユーザー登録のメニューを消したりしました。
その部分がもともとhref="{{ route('login') }}"
となっていたので、href="{{ url('auth/login/facebook') }}"
に修正。
ログイン……させるときって、どんなボタンでしたっけ……?
そもそもポップアップで動くボタンがFB側からは配布されてますけど、これを使ったほうがいいんでしょうか。
あ、VALUのイメージでいいのか。
とりあえず今回はそんな感じで。