LaravelのRoute設定で、同一階層(prefix)の中で認証あり、なしを分ける方法

LaravelのRoute設定を効率的にする方法をご紹介していきます。

一定慣れている方であれば、
・ディレクトリをまとめるために:prefix
・認証処理をまとめるために: middleware(‘auth’)
などを使うかたもいると思います。

これらを使う際に、同じディレクトリ階層だけども、認証が必要なページと、不要なページどちらもある、といったケースでの記述方法を紹介していきます。

やり方は色々とあります。

例えば、下記です。

 
Route::prefix('/article')->name('rec.')->group(function () {

    Route::get('/top', 'ArticleController@rec_top')->name('top');
    Route::get('/tag/{tag_id}', 'ArticleController@tag')->name('tag');

    Route::middleware('auth')->group(function () {
        Route::get('/postadd', 'ArticleController@postadd')->name('postadd');
        Route::post('/postdone', 'ArticleController@postdone')->name('postdone');
        });
});
 

まずは、下記のprefixで括ってしまいます。

 Route::prefix('/article')->name('rec.')->group(function () { }

その中に、

 Route::middleware('auth')->group(function () { }

括られるものと、括られないもので、認証あり、なしを分けていきます。

Laravel8のFactoryを使ってテストデータを作成する方法

Laravel8のFactoryを使ってテストデータを作成する方法を解説します。
Laravel8になって、Factoryの書き方が少し変わったので、そちらの紹介をしていきます。

細かい解説については、公式サイトの方で紹介されております。
是非確認してみてください。

データベースのテスト Laravel8

しかし、公式サイトは、Laravelへの(Factory・Seederへの)理解が十分であれば、サラッと理解できるかもしれません。
経験がまだ浅い方(私のように)には少しとっつき辛い部分もあると思います。

ざっくりとした、概要から解説していきたいと思います。

LaravelのFactoryとは何か

まず、Factoryとは何か。簡単に言うと、Laravelのデータベーステストにおいて、簡単に、そして大量にデータベースにデータを登録するための機能です。
Seederという機能はご存知でしょうか。
こちらも、データベースにテストデータを登録していく機能です。

Seederを単体で使う場合には、データを1つづつ自前で 記述していく必要があります。そこで、Factoryという機能をSeederと一緒に使うことによって、自前で記述しないで、Factoryに一定の指示をした通りに、ランダムなデータを大量に作成してくれます。

あまり理解できない人がいるでしょうか。

Seeder:登録したいデータを、そのまんま記述します。

user_id = 1 / name="taro" / email="taro@gmail.com"
user_id = 2 / name="jiro" / email="jiro@gmail.com"
user_id = 3 / name="saburo" / email="saburo@gmail.com"

Factory :必要な要素だけ指定して、ランダムにデータを作成

user_id = int型 / name = string型 / email = string型@gmail.com
3件データを作成

みたいな感じで、指定するとランダムでデータを作成してくれます。

Laravel8でのFactoryを活用したテストデータの作成方法を解説

まずは、ざっくりとした流れを解説していきます。

1; Factoryでデータ定義を作る
2:seederでファクトリーを設定
3: DatabaseSeeder で seeder callする
4: php artisan db:seed

1:Factoryでデータ定義を作る

Factoryですることは、作成するデータの定義を設定することです。
どんなカラムが存在しており、カラムのデータ型は何か、どんな値を設定したいのか(例えば、10桁のランダム文字列 など)などを指定していきます。

Factoryを設定するためには、Factoryファイルを作成する必要があります。
コマンドでファイルを作成していきます。

ChatMessageに利用するデータをFactoryを活用して作成していきます。
Modelは ChatMessage です。

 php artisan make:factory ChatMessageFactory 

これで、ChatMessageFactory のファイルが作成されます。

Laravel8での変更点としては、まずはこのデFactoryファイルでのデータ定義部分が変更されています。

public function definition(){}の中にデータの定義を記載していきます。

public function definition()
{
    return [
        'chat_room_id' => $this->faker->numberBetween($min = 1, $max = 10),
        'user_id' => $this->faker->randomDigit,
        'message' => Str::random(10),
        'created_at' => date('Y-m-d H:i:s'),
        'updated_at' => date('Y-m-d H:i:s'),
    ];
} 

chat_room_id、user_id、message、created_at、updated_atはデータベースのカラムの名称です。

これらのカラムに対して、fakerというものを使って、データの定義を決定していきます。

$this->faker->numberBetween($min = 1, $max = 10),

最低数が1、最大数が10の整数値 を作ってという指示です。

$this->faker->randomDigit,

ランダムの整数値 を作ってという指示です。

'message' => Str::random(10),

ランダムの10桁の文字列を作って、という指示です。

date('Y-m-d H:i:s'),

時刻表示の定義に合わせて、時間のデータを作って、という指示です。

こんな感じで、Factoryファイルでは、データの定義を記述していきます。

データの定義についたは、下記にて様々なデータ定義方法が記述されているので、自分のデータベースのカラムにあった指定をしてみてください。

https://github.com/fzaninotto/Faker

2:seederでファクトリーを設定

次にSeederで、Factoryを設定していきます。

ここも、Laravel8で記述方法が変わった部分かと思います。

まずは、Seederのファイルをコマンドで作成していきます。

 php artisan make:seed ChatMessageTableSeeder 

こちらのコマンドで、 ChatMessageTableSeeder ファイルが作成されます。

ChatMessageTableSeeder の全体を記述しておきます。
ここでのポイントは
ポイント①;eloquentを呼び出す
ポイント②:eloquentからfactoryを呼び出して、データ作成個数を設定する

下記が ChatMessageTableSeeder の全体です。

 <?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

// ChatMessage を呼び出し
use App\Models\ChatMessage;

class ChatMessageTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        ChatMessage::factory()->count(3)->create();
    }
}

 

->count(3) このメソッドで、作成するデータの個数を指定します。

3: DatabaseSeeder で seeder callする

ここまで、きたら後はすんなりいくと思います。

デフォルトである、DatabaseSeeder ファイルに対して、 ChatMessageTableSeeder を呼び出します。

記述方法は、public function run()メソッドの中でcallします。

     public function run()
    {
        $this->call(ChatMessageTableSeeder::class);
    } 

4: php artisan db:seed

最後に、php artisan db:seed をしてください。
これで、データベースを確認してください。
Factoryで指定したテストデータが作成されているかと思います。

以上です。
Laravel8で、変更された部分があるので、解説していきました。
是非、Factoryを使って、テストデータを作成してみ下さい。

DockerでLaravel構築した後に、bootstrapを導入。エラー祭りを解決

Dockerを使って、Laravelを起動しています。
昔、xamppでLaravelでbootstrapした際は、すんなりいったと思うのですが、
今回は色々なエラーに苦しんだので、記録して残しておきます。

Dockerの環境は、docker-composeを利用して、
php, nginx, mysqlを別々のコンテナで起動しています。

ざっくりとした流れはこちらです。

・php へbashでアタッチする
・node.jsをインストール
・laravel/ui導入
・bootstrap導入
・npm を install & run

php へbashでアタッチする

まずは、Dockerコンテナのphpの中に入ります。
php のコンテナ名はphp としております。

docker-compose exec php bash

cd コマンドを使って、Laravelアプリケーションのルートディレクトリへいきます。
artisan , composer などが存在するディレクトリです。

node.jsをインストール

その階層で、下記コマンドを別々に打ち込んでいきます。

apt-get install -y gnupg
curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install -y nodejs

laravel/ui導入

 composer require laravel/ui 

bootstrap導入

 php artisan ui bootstrap 

npm を install & run

 npm install && npm run dev 

そこで、下記のようなエラーがでてきました。

npm WARN deprecated popper.js@1.16.1: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1
 npm ERR! code ENOENT
 npm ERR! syscall rename
 npm ERR! path /work/app/node_modules/.vue-loader.DELETE/node_modules/source-map
 npm ERR! dest /work/app/node_modules/vue-loader/node_modules/source-map
 npm ERR! errno -2
 npm ERR! enoent ENOENT: no such file or directory, rename '/work/app/node_modules/.vue-loader.DELETE/node_modules/source-map' -> '/work/app/node_modules/vue-loader/node_modules/source-map'
 npm ERR! enoent This is related to npm not being able to find a file.
 npm ERR! enoent
 npm ERR! A complete log of this run can be found in:
 npm ERR!     /root/.npm/_logs/2020-10-06T03_43_21_673Z-debug.log

 こちらを見てみると、似たようなエラーが….

https://stackoverflow.com/questions/49651221/npm-enoent-no-such-file-or-directory-rename

 rm package-lock.json 

一度、package-lock.json を削除した後に
再度、

npm install && npm run dev 

これで、いけました!

DockerでMysqlへログイン ERROR 1045 (28000): Access denied for user

Dockerの環境構築に手こずっておりました。
今回の記事は、先日の記事の続きです。

mysqlの中に入ったあとに、

docker exec -it db-host bash

mysqlにrootユーザーとしてログインしようとしたら、次のようなエラーメッセージが表示されました。

root@5c001e56e8bc:/# mysql -uroot -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

Laravelの.envの確認をして、password設定したいましたが、うまくいきません。

結論:docker-compose.yml の MYSQL_ROOT_PASSWORDを確認

mysqlへのroot権限での情報は、docker-compose.yml > environment: > MYSQL_ROOT_PASSWORD: で設定していたのです….

理解せずに、進めると躓きますね。

ということで、ここで設定したpasswordを反映すると、下記のように入れます。

Welcome to the MySQL monitor.  Commands end with ; or \g.
 Your MySQL connection id is 3
 Server version: 5.7.31 MySQL Community Server (GPL)
 Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
 Oracle is a registered trademark of Oracle Corporation and/or its
 affiliates. Other names may be trademarks of their respective
 owners.
 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

DockerでLaravelを構築時に、Route設定したのに[404 not found]

Dockerを使ってLaravelの環境構築をしています。
DockerもLaravelもまだまだ理解が浅いなかで、進めています。

今回、解説したいことは、
・Dockerを使ってLaravelを構築
・トップページは表示 (welcom.blade.php)
・ルーティング、コントローラー、ビューを設定(ミスなく)
・新しく設定したルートをリクエストしても[404 not found]になる ★ココ

という状況です。

DockerのLaravel環境構築は、Qiitaで記載されていた下記を参考にさせて頂きました。

https://qiita.com/A-Kira/items/1c55ef689c0f91420e81

( ほぼ)同じようにセットアップしていきました。
上記問題が発生した際に、確認したことは。

ルーティングの設定です。
最初は、
Laravelのルート設定に問題がないのか確認したのですが、問題ありませんでした。

次に、
Webサーバーの確認です。
Webサーバー は、nginxを使っています。
で、Dockerにて、nginxを設定する際に、default.confで設定していた部分を確認しました。

nginx設定は、基本的にはdefault.confで設定していくそうです。
ここで、ルーティングと関係している部分は、 location  です。

元々の設定:

location / {     root /var/www/public;     index  index.html index.php;     } 

この場合だと、ルートディレクトリのみ表示できる状態です。

下記のように変更すると、設定した他のルートにもアクセスできました。
loacationの設定は 他にも、色々とありそうです。

  location / {
    root /var/www/public;     
  index  index.html index.php; 
    try_files $uri $uri/ /index.php?$query_string;    
  } 

これを変更したあとは、
再度、
・ビルドを実施。(キャッシュは使わずに)
・コンテナ起動
をして、確認してみましょう。

docker-compose build --no-cache
docker-compose up -d

Laravelで画像をUploadして、表示させる方法

Laravelで画像をUPLOADして、表示させる方法を紹介します。
今回は、POSTで画像をUploadしていきます。
・画像のUpload方法
・画像の表示方法
を紹介していきます。

画像をUploadするための流れを解説

・formを利用して、画像をUpload
・UploadするファイルのPathをデータベースへ保存

formを利用して、画像をUpload

まずは、formを利用して画像をUploadします。
formで、Uploadされた画像は、storageの配下にUPされます。

View____________________

<form method="POST" action="/imageUpload" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="file" id="file" name="profile" class="form">
<button type="submit">アップロード</button>
</form> 

ポイント;
・input type=”file”
・enctype=”multipart/form-data

ファイルアップロードをする場合input要素はを使い、その親のform要素には以下のようにenctype=”multipart/form-data”と書く必要があります。

ROUTE____________________

Route::post('/imageUpload', 'mypageContactController@imageUpload') 

ポイント;
・formのactionが、postで指定するアクション内容となる。

UploadするファイルのPathをデータベースへ保存

Uploadされた画像を呼び出すために、Uploadする画像のPath名称を設定して、そのPathをデータベースに登録する必要があります。

$file_name = time() . '.' . request()->file->getClientOriginalName();
// fileの名称を決定します。
// Uniqueになっていることが重要なので、time()を接頭に追記

$request->file('file')->storeAs('public',$file_name);
// storageは以下のpublicディレクションに、 $file_name で保存



//ここからは、データベースにファイルがUpされているPathを保存
$imagepath = '/storage/' . $file_name;


$loginId = Auth::id();
$profileInfo = User::find($loginId);
//Modelを活用

$profileInfo->imagepath = $imagepath;
// imagepathをデータベースへ保存
$profileInfo->save();

return redirect()->action(
'mypageContactController@profile'
); 

パス名が public/xxxxxxxxxx.jpg となるので不要な public/ の部分を削除しています。

画像を表示するための流れを解説

・シンボリックリンクの作成
・<img src=”path名称”>に、pathを代入する

シンボリックリンクの作成

Laravelは、publicディレクトリ配下に存在するファイルしか、表示することができません。しかし、アップロードしたファイルは/storage/appの下にあるためアクセスすることができません。
/publicディレクトリと/storage/appディレクトリとの間でリンクを持たせる必要があります。
それを実行してくれるのが、シンボリックリンクです。

やり方は、いたってシンプルです。
コマンドで下記を実行してください。

 $ php artisan storage:link 

画像を表示させる<img src=”path名称”>に、pathを代入する

あとは、画像を表示させたい場所で、保存したPathを呼び出してあげればよいです。上記で、App\Model\User {{ imagepath }} のカラムへ、Pathをデータベースへ保存しました。

Viewで下記を呼び出してあげればOKです。
※ただし、Viewで呼び出すために、Controllerから、profileInfo(Userのデータ)をView側へcompactで送ってあげることが前提です。

@if(isset( $profileInfo->imagepath ))
<img src="{{$profileInfo->imagepath}}">     
@else
@endif   

LaravelでSNS認証の後に、自動ログイン出来なかった問題を解決。※Guard利用者

LaravelでSNS認証の後に、自動ログイン出来なかった問題がありました。
事象としては、
・Laravelで Socialite を利用して、Twitter認証を作成
・初認証時は、登録→自動ログインの流れ
・データベースには、ユーザー情報は登録されているが、ログイン出来ず。

問題は、Guardを反映することが出来ていなかったことです。

サイトの作りとして、ログイン時に Auth::guard(‘company’)の認証を持つ作りになっていました。

今回の自動ログインでは、Auth:;login()を使っていました。

Auth::login($myinfo);
//$myinfoはユーザー情報

しかし、これでは、自動ログインすることが出来なかったのです。
認証を与えてあげていなかったのが原因です。
認証を与えて → ログインをさせてあげればよいです。
下記書き方で、自動ログインすることが出来ました。

Auth::guard('company')->login($myinfo);

この辺の記述は、 readouble にも記述されていましたので、参考にしてみてください。

https://readouble.com/laravel/5.7/ja/authentication.html

Twitter APIで、TwitterのEmailを取得。getEmail()が機能しなかった忘備録

LaravelでTwitterログイン機能を設定しようとしています。
LaravelでのSNS認証は、ライブラリの Socialite を使うのがオススメです。

今回は、Laravelでのコード内容ではなくて、Twitterに登録しているemailアドレスを取得するためのTwitter Developer上での設定方法を紹介します。

なぜ、この記事を書こうかと思ったかというと
下記のようにemailをTwitterアカウントから取得しようとしたのですが、$emailがnullで取得できなかったためです。

$user = Socialite::with("twitter")->user(); 
$email =  $user->getEmail();

問題は、Twitter Developer上の設定でした。

Authentication settingsで
Request email address from users is enabled に変更します。

こちらの設定をすることで、

$user = Socialite::with("twitter")->user(); 
$email = $user->getEmail();

$emailが取得することが出来ました。

Laravelでパスワードを、特定条件の文字列でハッシュ化する方法

Laravelでハッシュ化する際は、
ファザードで Hash::make(password);
を使うことが大半かと思います。

通常の使い方であればこれでいいと思います。
しかし、このhash方法だと、「\」「$」などの記号も含んだ値が返答されます。

そういった文字列は、都合が悪い場合があります。

その際に、一定の条件に従った文字列を返答してくれるハッシュ方法を紹介します。

MD5方式で、16進数・32文字のハッシュ値を生成する
数字とアルファベットも文字列を含んだ値のみを返します。

使い方はいたって簡単です。

md5(password);

することで、レスポンスされます。

まとめて紹介してくれている記事がありましたので、添付します。

Laravel Routeにnameを設定・使い方

Laravelでrouteを利用して、viewを呼び出す際に、Routeにnameを設定する方法を紹介します。

routes\web.php(Routeを設定しているファイル)で、nameを設定します。

 Route::get('/profile', 'mypageController@profile')->name('profile');

記載方法はRouteの最後に、
->name(route名称)でrouteの名称を設定することが出来ます。

nameを設定するメリットについては、Qiitaで分かりやすく解説している方がいたので、ご確認下さい。
Laravel使うならrouteには名前をつけたほうが良い

もう少し使い方について解説します。
Routeでのname設定は、名称を設定しただけです。
これを実際にnameを呼び出して使う方法を紹介します。

routeを使うときは、view bladeの中から呼び出します。

例えば、href にて、リンク先を/profileに設定したい際には、
先ほど、設定したnameを呼び出すカタチで下記のようにリンクに設定します。

<a class="nav-link" href="{{ route('profile') }}">Profile</a>

で、この例だと、ただ、リンクに飛ばしているだけじゃないか、と思うかもしれません。

ここで実験して欲しいのですが

Route:

 Route::get('/profile', 'mypageController@profile')->name('profile.gogogo');

View:

<a class="nav-link" href="{{ route('profile.gogogo ') }}">Profile</a>

と設定しても、/profileへリンクされるのです。
nameはただRouteを接続してくれているだけです。
Routeに設定してある、/profileへの接続は変わりません。

もう一点、私が少し混乱したことについて追記します。
Route設定で、group設定を使う人も多くいると思います。

例えば、下記のようにRoute設定した場合

Route::name('admin.')->group(function () {
   Route::get('/profile', 'mypageController@profile')->name('profile'); 
});

Viewでname を使って、Routeを呼び出す方法は

<a class="nav-link" href="{{ route(' admin.profile') }}">Profile</a>

group 化のname設定によって、nameがadmin.XXXXと設定する必要が出てきます。