この記事は、PHPのフレームワーク「Laravel」でTwitterのようなアプリを作成するための解説記事です。
私(わや@wayasblog)自身、Laravelを最近勉強し始めたので、かなり丁寧に解説した初心者向けの記事となっています。
コードだけ見たい!という方は、こちら(GitHub)からどうぞ。
今回は以下の記事を参考に、機能を少し追加してみました。

» Laravelで作成したアプリやアウトプットの一覧はこちら
スポンサーリンク
Laravelで作るTwitter風のSNSアプリのイメージ
スクリーンショットで紹介していきます。
今回は、Bootstrapで簡単にスタイルを作成しました。
タイムラインページ(未ログイン)

未ログイン状態だと、タイムラインは見れますがツイートはできません。
タイムラインページ(ログイン後)

ログイン後は、ツイートできるようになります。
ツイート時のバリデーション

何も入力せずにツイートボタンを押した時のバリデーション。

140文字以上入力した時のバリデーション。
ツイート時の動画

新しいツイートが1番上に挿入されます。
初期設定
お決まりの初期設定をしていきます。
Laravelのインストール
composer create-project --prefer-dist laravel/laravel laravel_sns
「laravel_sns」というフォルダの中に、Laravelがインストールされました。
phpMyAdimnでDB作成
今回は「laravel_sns」というDBを作成しました。
.envファイルの設定
DBの設定のため、.envファイルを編集します。
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_sns DB_USERNAME=root DB_PASSWORD=root
configファイルの設定
config/app.phpで日本語と時間の設定をします。
'timezone' => 'Asia/Tokyo', 'locale' => 'ja',
以上で、初期設定は終わりです。
ログイン機能の実装
Laravelでは、簡単にログイン機能を実装することができます。
composer require laravel/ui
php artisan ui vue --auth
以上の2つのコマンドを実行するだけ。
なぜかログイン画面などにBootstrapのCSSが読み込まれないので、resources/views/layouts/app.blade.phpで読み込ませます。
CSSやJSは、こちらからどうそ。

これでログイン機能の実装ができました。
コントローラーの作成
php artisan make:controller TimelineController
app/Http/Controllers/TimelineController.phpが作成されました。
ここに、以下のfunctionを作っていきます。
- showTimelinePage
 - postTweet
 
※postTweetは、DB挿入のためのものでページは作成しないので、viewは渡しません。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TimelineController extends Controller
{
    public function showTimelinePage()
    {
        return view('timeline');
    }
    public function postTweet()
    {
    }
}
ルーティングの設定
routes/web.phpを編集します。
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
Route::get('/timeline', 'TimelineController@showTimelinePage')->name('timeline');
Route::post('/timeline', 'TimelineController@postTweet')->name('timeline');
ビューの作成
resources/viewsにtimeline.balde.phpを作成します。
フォームは「Laravel Collective」の「Forms & HTML」を使うので、インストールします。
※参考:Laravel Collective
composer require laravelcollective/html
timeline.balde.phpの中身は以下の通りです。
@extends('layouts.app')
@section('content')
    <div class="container mt-3">
        {!! Form::open(['route' => 'timeline', 'method' => 'POST']) !!}
            {{ csrf_field() }}
            <div class="row mb-4">
                {{ Form::text('tweet', null, ['class' => 'form-control col-9 mr-auto']) }}
                {{ Form::submit('ツイート', ['class' => 'btn btn-primary col-2']) }}
            </div>
        {!! Form::close() !!}
    </div>
@endsection
モデルとマイグレーションの作成
モデルはDBとの連携を行う機能で、マイグレーションはDBを管理する機能です。
php artisan make:model Tweet -m
コマンドで-mを付けると、database/migrationsにマイグレーションファイルも一緒に作られるので、中身を書いていきましょう。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTweetsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tweets', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id');
            $table->text('name');
            $table->text('tweet');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('tweets');
    }
}
同時にapp/Tweet.phpが作成されるので、中身を書いていきます。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tweet extends Model
{
    protected $fillable = [
        'user_id',
        'name',
        'tweet',
    ];
}
ここまで完了したら、以下のコマンドでDBにテーブルが作成されます。
php artisan migrate
バリデーションの設定
app/Http/Controllers/TweetController.phpのpostTweetの中に書いていきます。
public function postTweet(Request $request)
    {
        $request->validate([
            'tweet' => 'required|max:140',
        ]);
    }
timeline.blade.phpにエラーを表示させます。
@extends('layouts.app')
@section('content')
    <div class="container mt-3">
        {!! Form::open(['route' => 'timeline', 'method' => 'POST']) !!}
            {{ csrf_field() }}
            <div class="row mb-4">
                {{ Form::text('tweet', null, ['class' => 'form-control col-9 mr-auto']) }}
                {{ Form::submit('ツイート', ['class' => 'btn btn-primary col-2']) }}
            </div>
            {{-- エラー表示 ここから --}}
            @if ($errors->has('tweet'))
                <p class="alert alert-danger">{{ $errors->first('tweet') }}</p>
            @endif
            {{-- エラー表示 ここまで --}}
        {!! Form::close() !!}
    </div>
@endsection
このままだと英語で表示されるので、日本語化していきます。
resources/langのenフォルダと同階層にjaフォルダを作成し、validation.phpをコピペ。
修正した箇所は以下の通りです。
'max' => [ 'string' => ':attributeは:max文字以内で入力してください。', ], 'required' => ':attributeは必ず入力してください。', 'attributes' => [ 'tweet' => 'ツイート', ],
ツイートした内容を、タイムラインで表示する
app/Http/Controllers/TweetController.phpに追記します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use \App\Tweet;
class TimelineController extends Controller
{
    public function showTimelinePage()
    {
        $tweets = Tweet::latest()->get();
        return view('timeline', [
            'tweets' => $tweets,
        ]);
    }
    public function postTweet(Request $request)
    {
        $request->validate([
            'tweet' => 'required|max:140',
        ]);
        Tweet::create([
            'user_id' => Auth::user()->id,
            'name'    => Auth::user()->name,
            'tweet'   => $request->tweet,
        ]);
        return back();
    }
}
実際にツイートをビューで表示していきます。
resources/views/timeline.blade.phpはこのようになりました。
@extends('layouts.app')
@section('content')
    <div class="container mt-3">
        {!! Form::open(['route' => 'timeline', 'method' => 'POST']) !!}
            {{ csrf_field() }}
            <div class="row mb-4">
                {{ Form::text('tweet', null, ['class' => 'form-control col-9 mr-auto']) }}
                {{ Form::submit('ツイート', ['class' => 'btn btn-primary col-2']) }}
            </div>
            @if ($errors->has('tweet'))
                <p class="alert alert-danger">{{ $errors->first('tweet') }}</p>
            @endif
        {!! Form::close() !!}
        @foreach ($tweets as $tweet)
            <div class="mb-1">
                <strong>{{ $tweet->name }}</strong> {{ $tweet->created_at }}
            </div>
            <div class="pl-3">
                {{ $tweet->tweet }}
            </div>
            <hr>
        @endforeach
    </div>
@endsection
ログイン状態でのみツイートできるようにする
ログイン状態のみツイートできるようにして、ログインしていない場合はタイムラインを見ることだけができるように条件分岐します。
resources/views/timeline.blade.phpを変更。
@extends('layouts.app')
@section('content')
    <div class="container mt-3">
        {!! Form::open(['route' => 'timeline', 'method' => 'POST']) !!}
            {{ csrf_field() }}
            <div class="row mb-4">
                {{-- 変更ここから --}}
                @guest
                    <div class="mx-auto">
                        <a class="btn btn-primary" href="{{ route('login') }}">ログインしてツイートする</a>
                        <a class="btn btn-primary" href="{{ route('register') }}">新規登録してツイートする</a>
                    </div>
                @else
                    {{ Form::text('tweet', null, ['class' => 'form-control col-9 mr-auto']) }}
                    {{ Form::submit('ツイート', ['class' => 'btn btn-primary col-2']) }}
                @endguest
                {{-- 変更ここまで --}}
            </div>
            @if ($errors->has('tweet'))
                <p class="alert alert-danger">{{ $errors->first('tweet') }}</p>
            @endif
        {!! Form::close() !!}
        @foreach ($tweets as $tweet)
            <div class="mb-1">
                <strong>{{ $tweet->name }}</strong> {{ $tweet->created_at }}
            </div>
            <div class="pl-3">
                {{ $tweet->tweet }}
            </div>
            <hr>
        @endforeach
    </div>
@endsection
ログイン、ログアウト後のリダイレクト先をタイムラインに変更
ログイン機能を実装した段階で、
- ログイン後 → /home
 - 新規登録後 → /home
 - ログアウト後 → /
 
とデフォルトで決まってしまっているので、これを直接タイムラインに行くように設定します。
app/Http/Controllers/Auth/LoginController.phpを変更
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */
    use AuthenticatesUsers;
    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = 'timeline';
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
    protected function loggedOut($request)
    {
        return redirect(route('timeline'));
    }
}
app/Http/Controllers/Auth/RegisterController.phpも上記と同じ箇所を変更します。
/** * Where to redirect users after registration. * * @var string */ protected $redirectTo = 'timeline';
resources/views/home.blade.phpは消しておきました。
以上で、簡単なものではありますが、Twitter風のSNSアプリの完成です。
お疲れさまでした\(^o^)/
【まとめ】簡単なTwitter風のSNSアプリの作成手順
Laravelを使うと、結構簡単にTwitter風のアプリができて感動しています。
これからもどんどんアウトプットしていこうと思います。
コード全体を見たい!という方は、こちら(GitHub)からどうぞ。
以上です。最後まで見てくださり、ありがとうございました。
» Laravelで作成したアプリやアウトプットの一覧はこちら
最後に宣伝
ココナラで、コーディングの相談を受け付けています。
- CSSが上手く作れない
 - JavaScriptが思ったように動かない
 - ブログのデザインを修正したい
 - 勉強中でわからないところがあるから教えてほしい
 
このようなお悩みを解決していますので、「こんなの解決できる?」ということがあったら、ぜひ質問だけでも以下のリンクよりどうぞ。


  
  
  
  

コメント