- 投稿日:2019-07-19T22:18:04+09:00
Laravelの機能、文法
MVCフレームワークに基づく構成
view
app/resources/view
$ php artisan make:controller
app/Http/Controllers
$ php artisan make:controller {ファイル名}DB接続
use Illuminate\Support\Facades\DB;app/resources/view/home.blade.php にアクセス
usersのテーブルを取得するpublic function index() { $users = DB::table('users')->get(); return view('home'); }トランザクション処理
public function index(){ DB::beginTransaction(); try{ //処理 DB::commit(); //成功して処理する }catch(/Exception $e){ DB::rollback(); //失敗時処理されない } }model
app/database/factories
$ php artisan make:model {ファイル名}ルーティング
app/routes
Route::get('/', 'HomeController@index');トップページの時、HomeControllerのクラスのindexメソッドを呼び出す。
マイグレーション
app/database/migrations
マイグレーションファイルの作成$ php artisan make:migration {ファイル名}DBへテーブルを作成する
$ php artisan migratepublic function up() { Schema::create('{テーブル名}', function (Blueprint $table) { $table->string('{カラム名}'); }); }ロールバック時の処理
$ php artisan migrate:rollbackpublic function doun() { Schema::create('{テーブル名}', function (Blueprint $table) { $table->string('{カラム名}'); }); }マイグレーションのカラム更新パッケージインストール
composer require doctrine/dbalseed
app/database/seeds
$ php artisan db:seedseedの実行
database/seeds/DatabaseSeeder.php に実行する設定を記載する。日本語に変換
app/config/app.php'faker_locale' => 'ja_JP',インサート文
$result = DB::table('{テーブル名}')->insert([ '{カラム名}' => '', ]);ログイン
$ php artisan make:auth
- 投稿日:2019-07-19T22:18:04+09:00
Laravelの機能、ルール
MVCフレームワークに基づく構成
view
app/resources/view
$ php artisan make:CSRF対策の記述
<from method="post" action=""> @csrf </from>controller
app/Http/Controllers
$ php artisan make:controller {ファイル名}app/resources/view/home.blade.php にアクセス
usersのテーブルを取得するuse Illuminate\Support\Facades\DB; public function index() { $users = DB::table('users')->get(); return view('home'); }トランザクション処理
public function index(){ DB::beginTransaction(); try{ //処理 DB::commit(); //成功して処理する }catch(/Exception $e){ DB::rollback(); //失敗時処理されない } }model
app/database/factories
$ php artisan make:model {ファイル名}論理削除の記述
use Illuminate\Database\Eloquent\SoftDeletes; class Friend extends Model { use SoftDeletes; protected $dates = ['{カラム名}']; }作成されたクラスは、同じ名前のテーブルと同期する。
Friendクラスとfriendsテーブルが自動で同期するルールとなる。
ルールに反している場合、Friendクラスで指定する
またプライマリーキーがid以外の場合も指定するclass Friend extends Model { protected $table = '{テーブル名}'; protected $primaryKey = '{プライマリーキーのカラム名}'; }アクセサの方法
アクセサの定義を行うと、予め取得するカラムのフォーマットを定義できる。class Friend extends Model { public function get{プロパティ名}Attribute{ return $this->{プロパティ名}.$this->{任意の文字}; } }viewでプロパティ名を指定して表示できる。
ルーティング
app/routes
Route::get('{URL}','{コントローラー名}@{メソッド名}');マイグレーション
app/database/migrations
マイグレーションファイルの作成$ php artisan make:migration {ファイル名}DBへテーブルを作成する
$ php artisan migratepublic function up() { Schema::create('{テーブル名}', function (Blueprint $table) { $table->string('{カラム名}'); }); }ロールバック時の処理
$ php artisan migrate:rollbackpublic function doun() { Schema::create('{テーブル名}', function (Blueprint $table) { $table->string('{カラム名}'); }); }マイグレーションのカラム更新パッケージインストール
$ composer require doctrine/dbalseed
app/database/seeds
$ php artisan db:seedseedの実行
database/seeds/DatabaseSeeder.phpに実行する設定を記載する。日本語に変換
app/config/app.php'faker_locale' => 'ja_JP',インサート文
$result = DB::table('{テーブル名}')->insert([ '{カラム名}' => '', ]);バリデーション
コントローラーのメソッドに記載する。
区切ることでバリデーションを複数指定できる。use App/rules/{独自バリデーションクラス名}; public function index(Reqest $reqest) { $reqest->validate([ '{name名}' => '{バリデーション}|{バリデーション}', '{name名}' => '['{バリデーション}',new {独自バリデーションクラス名}]' ]); }エラー文の日本語化
resources/lang/en/validation.phpのバリデーション内容が表示される。
resources/lang/ja/validation.phpファイルを作成し日本語を記入する。
config/app.phpをjaに変更する。'locale' => 'ja',独自のバリデーションを追加する。
$ php artisan make:rule {クラス名}app/Rules/{クラス名}.php
public function passes($attribute, $value) { if(preg_match({正規表現},$value){ return true; }else{ return false; } }viewのバリデーションエラーの記載
@if($errors->any()) @foreach($errors->all() as $error) {{ $error }} @endforeach @endifログイン
$ php artisan make:auth
- 投稿日:2019-07-19T22:16:16+09:00
Laravelインストール手順
Laravelとは
Laravelは、フルスタックなPHPフレームワークで、ルーティング、コントローラ、ビュー、ORMなど基本的な機能を備え、さらに近代的なWebアプリで活用されるジョブキューやWebストレージなども積極的に統合している。
MITライセンスの下でリリースされており、そのソースコードはGitHubにホスティングされている。
Laravelインストールの流れ
composerをインストール。
composerを使ってLaravelをインストール。composerとは
PHP用のパッケージを管理するためのツール
composerのインストール
ComposerをPHPのパッケージ管理システムをインストールします。
$ curl -sS https://getcomposer.org/installer | phpcomposer.pharが存在する階層にいる場合、composerコマンドが使える。
どこでもcomposerコマンドが使えるようにcomposer.pharを下記のとする。$ mv composer.phar /usr/local/bin/composer移動後、ターミナルで
$ composer --versionコマンドを実行しバージョン番号を確認します。
Laravelのインストール
Composerで専用インストーラをインストールします。
$ composer global require "laravel/installer=~1.1"Laravelコマンドが実行できるように、~/.composer/vendor/bin
(Windowsの場合は、C:\%HOMEPATH%\AppData\Roaming\Composer\vendor\bin)
ディレクトリにPATHを通します。$ export PATH="$PATH:~/.composer/vendor/bin"以下のようにコマンド1つでLaravelプロジェクトが作成できます。
$ laravel new [プロジェクト名]動作確認
プロジェクトのルート(プロジェクト名)に移動し、
$ php artisan serveを実行すると、
Laravel development server started on http://localhost:8000/と表示されるので、ブラウザでhttp://localhost:8000/にアクセスしてみます。
このような画面が表示されれば、環境構築完了。
- 投稿日:2019-07-19T18:56:53+09:00
LaravelでClass 'FooProvider' not foundが解決できない場合
一度configのapp.phpに記述した後に、消した場合に発生する。
こんな感じのエラーメッセージ。Class 'Aws\Laravel\AwsServiceProvider' not foundconfigを読み直しても、
php artisan config:cachecomposer dump-autoloadしなおしても
composer dump-autoloadなおらない。
なぜなら、クリアしてもbootstrap/cache/config.php に残っているからだ。こいつを削除すればOK
- 投稿日:2019-07-19T18:06:32+09:00
Laravel 5.8 認証
認証
laravelだと以下のコマンドで認証機能に加えて
ログインユーザー登録とパスワードリセットのメール送信、
ユーザー登録時のメール確認なども付いている。make:auth
以下のコマンドで認証に必要なControllerとviewが一式コピーされる。
$ php artisan make:authroutes/web.phpに以下の記載が追加される。
routes/web.php(略) Route::resource('users', 'UserController'); // 以下が追加される Auth::routes(); Route::get('/home', 'HomeController@index')->name('home');route::listに以下のルーティングが追加される。
$ php artisan route:list | | GET|HEAD | home | home | App\Http\Controllers\HomeController@index | web,auth | | | POST | login | | App\Http\Controllers\Auth\LoginController@login | web,guest | | | GET|HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest | | | POST | logout | logout | App\Http\Controllers\Auth\LoginController@logout | web | | | POST | password/email | password.email | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail | web,guest | | | GET|HEAD | password/reset | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest | | | POST | password/reset | password.update | App\Http\Controllers\Auth\ResetPasswordController@reset | web,guest | | | GET|HEAD | password/reset/{token} | password.reset | App\Http\Controllers\Auth\ResetPasswordController@showResetForm | web,guest | | | GET|HEAD | register | register | App\Http\Controllers\Auth\RegisterController@showRegistrationForm | web,guest | | | POST | register | | App\Http\Controllers\Auth\RegisterController@register | web,guest |この時点で/loginにアクセスするとログイン画面が表示される。
layouts/app.blade.php
make:authで作成されます。bootstrapのnav-barで実装されていて
ログインしていないと「ログイン」「登録」メニューが表示され
ログインすると「ログイン」「登録」が非表示、
代わりにログインユーザメニューと「ログアウト」のサブメニューが表示される。このapp.blade.phpでコンテンツ部と分けられているので
既存のユーザー管理画面もそれに倣って変更する。@yield('content')でコンテンツ部を表示するように設定。
*.blade.phpの設定
@extends('layouts.app');で上記レイアウトファイルを呼び出す。
@section('content')~@endsection('content')で
囲んだ内容が展開される認証の実装
各コントロールのconstructで行う。
ユーザーコントロールのconstructで設定するapp/Http/Constrollers/UsersController.phppublic function __construct() { $this->middleware('auth'); // 全アクセスにログイン認証が必要 // ->except・・・認証を除外するアクション配列 // ->only・・・認証が必要なアクション配列 }
php artisan route:listでusers系のアクションのmiddleware列で
authが追加されているのが確認できる。ログイン後、/homeに遷移するようになっています。
変える場合はapp/Http/Conrollers/Auth/配下のファイルの$redirectToの値を変更する
RegisterController.php
VerificationController.php
ResetPasswordController.php
LoginController.phpnav-barへのユーザー一覧メニューの追加
app.blade.phpにメニューを追加。ただしログインしている場合
resources/views/layouts/app.blade.php<!-- Left Side Of Navbar --> <ul class="navbar-nav mr-auto"> <!-- Main Menu Links --> @auth <li class="nav-item"> <a class="nav-link" href="{{ url('users') }}">{{ __('Users') }}</a> </li> @endauth </ul>
@auth~@endauthでログイン状態の条件、
@guest~@endguestでゲスト(非ログイン)状態の条件この時点では、だれでもユーザー登録がし放題なので登録時にメール確認する機能を追加
メール確認
Laravel 5.8 メール確認
上記の実装通りに進める。モデルの修正
app/User.php//class User extends Authenticatable class User extends Authenticatable implements MustVerifyEmail { (略)DB修正
usersテーブルに
email_verified_atカラムを追加する必要があるが5.8では標準で含まれている。ルーティングを変更
routes/web.php//Auth::routes(); Auth::routes(['verify' => true]);これだけでメール確認の機能が実装されます。
但し、厳密にはメールでの登録手続きが完了する前にログインできてしまうので
認証方法を変える必要がある。middlewareのverifiedの設定
各コントローラクラスのコンストラクタでmiddlewareを呼び出し制限する。
app/Http/Controllers/UserController.phppublic function __construct() { // ログイン済(メール認証済不問) // $this->middleware('auth'); // メール認証済 $this->middleware('verified'); // usersの全アクションにメール認証済が必要 }
- 投稿日:2019-07-19T17:34:03+09:00
LaravelからSESでメール送信ができなかったときの確認項目
前回(AmazonSESを使ったメールの受信に苦労した話)に引き続き、SES関連のお話。
エラーメッセージはというと、SignatureDoesNotMatchということで、認証できていないかんじ。
configファイルもenvファイルも何度も何度も見直したけど、正しい値を入れている自信はあった。
(実際には間違っていたから送信できなかった。)Aws/Ses/Exception/SesException with message 'Error executing "SendRawEmail" on "https://email.us-west-2.amazonaws.com"; AWS HTTP error: Client error: `POST https://email.us-west-2.amazonaws.com` resulted in a `403 Forbidden` response: <ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/"> <Error> <Type>Sender</Type> <Code>SignatureDo (truncated...) SignatureDoesNotMatch (client): The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. - <ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/"> <Error> <Type>Sender</Type> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message> </Error> <RequestId>196ba786-9d8c-4d78-bf10-052eff69e893</RequestId> </ErrorResponse>間違っていた箇所と解決策
まず必要な設定は、公式にも記載されているとおり、SESドライバのインストールとconfigファイルの変更。
https://readouble.com/laravel/5.8/ja/mail.html'ses' => [ 'key' => env('SES_KEY'), 'secret' => env('SES_SECRET'), 'region' => env('SES_REGION', 'us-east-1'), ],で、自分が間違っていたのは、SES_KEYとSES_SECRETの値。
AWSコンソールの、SES > SMTP Settings > Using SMTP to Send Email with Amazon SESで作成したユーザーIDとパスワードを入れていた。
実際は、IAM > ユーザー > (SESのwrite権限のあるユーザー) > 認証情報 > アクセスキーの作成 で作ったキーを入力。解決法が間違っていたら教えてくださいm(_ _)m
- 投稿日:2019-07-19T16:57:30+09:00
【Laravel】リレーション先のデータ取得方法を調べた
LaravelのEloquent ORMは、テーブル間のリレーションを管理・操作する際の独自の表現があります。
Laravel5.8 Eloquent:リレーション"1対多"や"多対多"のリレーションなどはよく使うのではないでしょうか。
今回は、これらのリレーションを定義したのち、実際にリレーション先のテーブルのデータをどうやって取得するのか、いくつか手法を調べました。※ここから先は、予めモデルクラスに以下のリレーションを定義したという前提で進めます。
ブログサイトなどで、1人のユーザーが複数の投稿を登録しているという想定です。User.phppublic function posts() { return $this->hasMany('App\Posts'); }
1.メソッドで呼び出す
マニュアルに記載されている、基本のやり方です。
User.php// ユーザーに紐づく投稿を全て取得し、Collectionで返す public function getPosts() { return $this ->find(1) ->posts() ->get(); } // 条件を付け加えることももちろん可能 // ユーザーに紐づく投稿について、題名で部分一致検索するものをCollectionで返す public function getPostByTitle() { return $this ->find(1) ->posts() ->where('title', 'LIKE', '%hoge%') ->get(); }
postsメソッドが呼び出されると、システムはPostsモデルクラスを参照します。
ですから、通常のモデルクラスの操作と同じように、メソッドチェーンであらゆる条件などを追加できます。公式マニュアル曰く
Eloquentは「動的プロパティ」を提供しているので、モデルのプロパティとして定義したリレーションメソッドへアクセスできる
ということで、以下の書き方も可能です
User.phppublic function getPosts() { return $this ->find(1) ->posts; //プロパティで呼び出す }さて、筆者も初めはこの方法で全てなんとかなると思っていましたが…ちょっとした落とし穴がありました。
というのも、上記のメソッドで取得できるのは特定のユーザーに紐づく、投稿のデータのみであるため、例えばユーザーのデータと投稿のデータを同時に返したいという場合や、ある条件を満たすユーザーに紐づく投稿を取得するといった場合に不都合が生じたのです。User.phppublic function findPostByUserIsOver25yo() { return $this ->where('age', '>', '25') ->get() ->posts; //get()した時点でcollectionオブジェクトになっており、collectionからpostsプロパティを呼び出そうとしているため、エラーになる }そのような時はどうすればよいのでしょうか?
2.withメソッドを用いる
このような場合は、
with()メソッドを使うとうまくいくようです。
参考にさせていただきました(公式マニュアルよく読んだらひっそりと使われていた…調べて存在を知るまで気がつかなかった)
User.phppublic function findPostByUserIsOver25yo() { return $this ->with('posts') ->where('age', '>', '25') ->get(); }このように取得すると、 各
UserモデルクラスのrelationsプロパティにPostモデルクラスが紐づいた状態になり、条件に合うユーザーのユーザー情報と投稿データを一度に取得できます。まとめ
両者を比較した上で、筆者の意見としては全部withでよくね?というのが正直なところです。
特に親テーブルのデータが不要で小テーブルの情報だけ取得したいという場合は、メソッドで呼び出すのがいいのだと思いますが、結局relationsプロパティで呼び出せるしなぁ…
もう少し色々な挙動を試してみたいです。ご意見・ご指摘などありましたらコメントお寄せください。
- 投稿日:2019-07-19T16:01:22+09:00
LaravelのDocker環境開発で2つDB作ってWeb用と単体テスト用DBに分けといて開発中はコマンド1つで両方リセットしとく。
- DBをWeb用と単体テスト用の2つ用意する。
- 開発中はDB定義更新したらリセットして最新反映してWeb用のみシーダーを実行したい。
Dockerでテスト用のDBを作成する
テストDBを作成するSQLファイルを設置する
- ./mysql/init/createdb.sql
- test_databaseという名前のDBを作成
mysql/init/createdb.sqlCREATE DATABASE IF NOT EXISTS `test_database` COLLATE 'utf8_unicode_ci' ; GRANT ALL ON `test_database`.* TO `docker` ;
- dbのvolumesで./mysql/initディレクトリにdocker-entrypoint-initdb.dを割り当てる
docker-compose.yml...省略 db: image: mysql:5.7 command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: web_database MYSQL_USER: docker MYSQL_PASSWORD: docker volumes: - db-data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d <-ここです。 networks: - dockernetworks networks: docker-net: volumes: db-data:
- ボリュームを消して反映させる
docker-compose down docker volume rm hoge_db-data docker-compose up単体テスト用DBの設定
.env.testing作成
env.testingAPP_ENV=testing APP_KEY=xxxxxxxxxx APP_DEBUG=true DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=test_database DB_USERNAME=docker DB_PASSWORD=docker単体テスト実行
% docker-compose exec app php vendor/bin/phpunit開発中のDB更新
DBリフレッシュコマンド作成
% docker-compose exec app php artisan make:command DBRefreshCommandapp/Console/Commands/DBRefreshCommand.php<?php namespace App\Console\Commands; use Illuminate\Console\Command; class DBRefreshCommand extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'db:refresh'; /** * The console command description. * * @var string */ protected $description = 'DB Refresh'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { if (env('APP_ENV') === 'local' && env('APP_DEBUG') === true) { $this->info('Refresh DB [Web用]'); $this->call('migrate:refresh', ['--seed' => 1]); $this->info('Refresh DB [単体テスト用]'); $this->call('migrate:refresh', ['--env' => 'testing']); } else { $this->error('開発のみ使用のコマンドです。'); } } }app/Console/Kernel.php/** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ App\Console\Commands\DBRefreshCommand::class, ];リフレッシュコマンド実行
% docker-compose exec app php artisan db:refresh Refresh DB [Web用] Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.01 seconds) Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.05 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.04 seconds) Database seeding completed successfully. Refresh DB [単体テスト用] Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.01 seconds) Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.03 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.03 seconds)
- 投稿日:2019-07-19T16:01:22+09:00
LaravelのDocker環境開発で2つDB作ってWeb用と単体テスト用に分けといて開発中はコマンド1つで両方リセットしとく。
- DBをWeb用と単体テスト用の2つ用意する。
- 開発中はDB定義更新したらリセットして最新反映してWeb用のみシーダーを実行したい。
Dockerでテスト用のDBを作成する
テストDBを作成するSQLファイルを設置する
- ./mysql/init/createdb.sql
- test_databaseという名前のDBを作成
mysql/init/createdb.sqlCREATE DATABASE IF NOT EXISTS `test_database` COLLATE 'utf8_unicode_ci' ; GRANT ALL ON `test_database`.* TO `docker` ;
- dbのvolumesで./mysql/initディレクトリにdocker-entrypoint-initdb.dを割り当てる
docker-compose.yml...省略 db: image: mysql:5.7 command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: web_database MYSQL_USER: docker MYSQL_PASSWORD: docker volumes: - db-data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d <-ここです。 networks: - dockernetworks networks: docker-net: volumes: db-data:
- ボリュームを消して反映させる
docker-compose down docker volume rm hoge_db-data docker-compose up単体テスト用DBの設定
.env.testing作成
env.testingAPP_ENV=testing APP_KEY=xxxxxxxxxx APP_DEBUG=true DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=test_database DB_USERNAME=docker DB_PASSWORD=docker単体テスト実行
% docker-compose exec app php vendor/bin/phpunit「test」DBの設定
- コネクションのmysqlをコピーしてmysql_testing作成、databaseを「test」にする
config/database.php'mysql' => [...省略...], 'mysql_testing' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => 'test', 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ],開発中のDB更新
DBリフレッシュコマンド作成
% docker-compose exec app php artisan make:command DBRefreshCommandapp/Console/Commands/DBRefreshCommand.php<?php namespace App\Console\Commands; use Illuminate\Console\Command; class DBRefreshCommand extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'db:refresh'; /** * The console command description. * * @var string */ protected $description = 'DB Refresh'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { if (env('APP_ENV') === 'local' && env('APP_DEBUG') === true) { $this->info('Refresh DB [Web用]'); $this->call('migrate:refresh', ['--seed' => 1]); $this->info('Refresh DB [単体テスト用]'); $this->call('migrate:refresh', ['--database' => 'mysql_testing']); } else { $this->error('開発のみ使用のコマンドです。'); } } }app/Console/Kernel.php/** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ App\Console\Commands\DBRefreshCommand::class, ];リフレッシュコマンド実行
% docker-compose exec app php artisan db:refresh Refresh DB [Web用] Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.01 seconds) Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.05 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.04 seconds) Database seeding completed successfully. Refresh DB [単体テスト用] Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds) Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table (0.01 seconds) Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.03 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.03 seconds)
- 投稿日:2019-07-19T15:51:03+09:00
Laravel 5.8 メール
認証機能のうちユーザー登録にメール確認を行うことができるようなので
予めメール送信の設定を行う。メール設定
.envファイルかconfig/mail.phpで行う。
MAIL_DRIVER=smtp MAIL_HOST=smtp.hoge.com MAIL_PORT=587 MAIL_USERNAME=hoge.admin@example.com MAIL_PASSWORD=(パスワード) MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS=hoge.admin@example.com MAIL_FROM_NAME="hoge admin"以下のコマンドでテスト送信。nullが変えればOK。
$ php artisan tinker Psy Shell v0.9.9 (PHP 7.2.20 ? cli) by Justin Hileman >>> Mail::raw('Test Mail', function($message) { $message->to('hoge@example.com')->subject('TEST Title'); }); => null >>>gmail等の場合、
MAIL_ENCRYPTION=nullをtlsにする必要があるが環境によっては
PHP Warningとなる。$ php artisan tinker Psy Shell v0.9.9 (PHP 7.2.20 ? cli) by Justin Hileman >>> Mail::raw('Test Mail', function($message) { $message->to('hoge@example.com')->subject('TEST Title'); }); PHP Warning: stream_socket_enable_crypto(): Peer certificate CN=.... >>>sslの厳密な検証を行うと証明書がドメインに含まれてないからエラーとなっている模様。
以下の設定を追加するとWarningを無視する。config/mail.php'stream' => [ 'ssl' => [ 'allow_self_signed' => true, 'verify_peer' => false, 'verify_peer_name' => false, ], ],参考URL
How to deal with self-signed TLS certificates in Laravel's SMTP driver?
- 投稿日:2019-07-19T14:39:46+09:00
Laravel 5.8 多言語化対応
言語ファイル
標準で用意されているのは以下の4つ
./resources/lang/en/auth.php,password.php,pagination.php,validation.php上記のファイルについてはLaravel側で予め用意しているがカスタマイズも可能
また以下のコマンドで標準で用意されている日本語版が導入される$ php -r "copy('https://readouble.com/laravel/5.8/ja/install-ja-lang-files.php', 'install-ja-lang.php');" $ php -f install-ja-lang.php $ php -r "unlink('install-ja-lang.php');"展開先は./resources/lang/ja/
多言語対応
Laravel 5.8 多言語化
上記4ファイル以外のメッセージの定義は各言語フォルダにmessages.phpとするか
/resources/lang/配下に言語2文字.json(ja.json / es.jsonなど)でjson形式で用意する。
key側はデフォルト言語(英語が無難か)多言語切り替え
https://qiita.com/kumamon_engineer/items/4a83344744db605e3e52
こちらを参考にさせてもらいました。デザインだけnav-bar用に変更
resources/views/layouts/app.blade.php(略) <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="javascript:void(0)" id="dropdown-lang" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ Config::get('languages')[App::getLocale()] }} </a> <div class="dropdown-menu dropdown-menu-right" aria-lledby="dropdown-lang"> @foreach (Config::get('languages') as $lang => $language) <a class="dropdown-item" href="{{ route('lang.switch', $lang) }}">{{ $language }}</a> @endforeach </div> </li> (略)
- 投稿日:2019-07-19T12:27:01+09:00
【Laravel5】認識機能を実装した際に追加される「Auth::routes()」にオプションを指定してカスタマイズする
php artisan make:authは便利だけど登録機能は別で作りたいという場合があると思うので、標準で実装される登録機能のルーティングを外してみたりしてみます。
(※Laravel5.7系以上)ソース
php artisan make:authを実行後、ルーティングに以下のコードが自動追加されると思うので、こいつに引数を渡していくroutes\web.phpAuth::routes();
Auth::routes()に対して以下のようにオプションで引数をbooleanで渡してやるとルーティングの設定をON/OFFできるroutes\web.phpAuth::routes([ 'verify' => true, // メール確認機能(※5.7系以上のみ) 'register' => false, // デフォルトの登録機能OFF 'reset' => true, // メールリマインダー機能ON ]);上記のルーティング情報は以下の通り。
registerが消えてverifyが追加されていると思います。
大本のソースは以下(
laravel\framework\src\Illuminate\Routing\Router.php)にあります。
コードを見てもらったらわかると思いますが、デフォルトでregister(登録機能)とreset(パスワードリマインダー)はスカフォールディングした段階で有効になるように書かれています。
(以下のソースはLaravel5.8系なので、新機能のメール確認機能のverifyが記述されていてかつデフォルトで無効になるようになっています)laravel\framework\src\Illuminate\Routing\Router.php/** * Register the typical authentication routes for an application. * * @param array $options * @return void */ public function auth(array $options = []) { // Authentication Routes... $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); $this->post('login', 'Auth\LoginController@login'); $this->post('logout', 'Auth\LoginController@logout')->name('logout'); // Registration Routes... if ($options['register'] ?? true) { $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); $this->post('register', 'Auth\RegisterController@register'); } // Password Reset Routes... if ($options['reset'] ?? true) { $this->resetPassword(); } // Email Verification Routes... if ($options['verify'] ?? false) { $this->emailVerification(); } }おわり
- 使用してない機能はルーティングをOFFにして不要なコントローラーは削除しておきましょう
- ただし、↑の引数で設定を切り替えられるのは5.7系以前は実装されてないみたいなので注意してください。
- 投稿日:2019-07-19T12:20:14+09:00
【Laravel5】たまに出てくる「the page has expired due to inactivity. please refresh and try again」を表示させない
多くの原因はCSRFトークンを記述していない場合で発生する
ググってみると多くの場合はフォーム内にCSRFトークンの記述漏れで発生していることが多いようです。
なのでまずはフォーム内にCSRFトークンの記述があるかを確認してください
Laravel5.6以前なら{{ csrf_field() }}を、
Laravel5.6系以降なら@csrfというシンプルに記述できるので、これをフォーム内に埋め込んでください。以下Laravel5.6以前の記述例
form.blade.php<form method="POST" action="/profile"> {{ csrf_field() }} ... </form>以下Laravel5.6系以降の記述例
form.blade.php<form method="POST" action="/profile"> @csrf ... </form>以下参考になるのかもしれませんが少し情報が古いので注意
【Laravel】TokenMismatchExceptionが発生する原因 - QiitaCSRFトークンの有効期限切れで表示される
CSRFトークンの有効期限切れで表示される場合(例えばログイン画面で長時間放置してからログインしたりする)
以下のような画面が表示され、リロードしろと促されます。正直、この画面がでても何のことかわからないし、あまりにも突然表示されたりするので、
CSRFトークンが有効期限切れの状態でログインしたりした際、ログイン画面へリダイレクトさせる処理をapp/Exceptions/Handler.phpに記述していきます。laravel\app\Exceptions\Handler.php<?php namespace App\Exceptions; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Session\TokenMismatchException; // add use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; class Handler extends ExceptionHandler { // ... /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $exception * @return \Illuminate\Http\Response */ public function render($request, Exception $exception) { // 「the page has expired due to inactivity. please refresh and try again」を表示させない if ($exception instanceof TokenMismatchException) { return redirect('/login')->with('message', 'セッションの有効期限が切れました。再度ログインしてください。'); } return parent::render($request, $exception); } }これで
TokenMismatchExceptionが発生した場合はログイン画面へエラーメッセージとともにリダイレクトさせることができるステータスコード(419)の場合にリダイレクトさせる
ちなみにステータスコードで判定するようにもできるので以下のようにも書けます。
laravel\app\Exceptions\Handler.php<?php namespace App\Exceptions; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Support\ViewErrorBag; // add use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; // add class Handler extends ExceptionHandler { // ... /** * Render the given HttpException. * * @param \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e * @return \Symfony\Component\HttpFoundation\Response */ protected function renderHttpException(HttpExceptionInterface $e) { $this->registerErrorViewPaths(); // 「the page has expired due to inactivity. please refresh and try again」を表示させない if ($e->getStatusCode() === 419) { return return redirect('/login'); } if (view()->exists($view = "errors::{$e->getStatusCode()}")) { return response()->view($view, [ 'errors' => new ViewErrorBag, 'exception' => $e, ], $e->getStatusCode(), $e->getHeaders()); } return $this->convertExceptionToResponse($e); } }ただステータスコード
419が必ずしもCSRFトークンの有効期限切れで返しているかわからないので、TokenMismatchExceptionが発生した場合のみログイン画面へリダイレクトさせた方がいいかなと思っていますがどうでしょう?おわり
- もっといい方法あれば教えていただきたいです草々不一
参考URL
- 投稿日:2019-07-19T12:02:12+09:00
Laravel で updateOrCreate を使う際に Unknown column 'id' in 'where clause' でハマった
概要
Laravel の Eloquent が持っている updateOrCreate という関数を使った。
https://readouble.com/laravel/5.7/ja/eloquent.htmlMySQL でも気軽に Upsert 処理ができて便利だと思った。
実装例
App\VeryGoodSystem::updateOrCreate(
['user_id' => 12345],
['is_registered' => true]
);いざ利用してみたところ、下記のようなエラーが出た。
Unknown column 'id' in 'where clause' ...エラーを追うと、 updateOrCreate で実行されている SQL 文に
where `id` is nullという条件が付いていることがわかった。コードを見ても、
idという変数を使っている所は無く、途方に暮れながら調べていたら、良い Q&A を見つけた。(最下部、参考サイト)つまり、 model に primaryKey が設定されていないと default で id という文字列を使って updateOrCreate 用の SQL を作成してしまうようだった。
利用している Model に
$primaryKey = 'user_id'の一行を追加することで解決した。参考サイト
https://laracasts.com/discuss/channels/eloquent/understanding-of-updateorcreate
- 投稿日:2019-07-19T10:49:32+09:00
DockerにLaravel環境を構築する
Docker/Laravel環境構築の備忘録です。
ゴールは、Docker上でLaravelが動くまでです。Macで実施します。
フォルダ構成/ファイルについて
今回は、以下のディレクトリ構成としました。
treeproject ├── docker │ ├── db │ │ ├── Dockerfile ① │ │ ├── conf.d │ │ │ └── my.cnf ② │ │ ├── data ③ │ │ └── initdb.d ④ │ ├── docker-compose.yml ⑤ │ └── web │ ├── Dockerfile ⑥ │ ├── conf.d │ │ └── 000-default.conf ⑦ │ └── ini │ └── php.ini ⑧ └── laravel ⑨順番に説明します。
① project/docker/db/Dockerfile
Dockerコンテナの構成内容を記述します。
ここでは、Dockerイメージとして、MySQLを指定しています。project/docker/db/DockerfileFROM mysql:5.7② project/docker/db/conf.d/my.cnf
MySQLの設定ファイルです。
⑤にて、/etc/mysql/conf.d にマウントします。project/docker/db/conf.d/my.cnf[mysqld] character-set-server=utf8mb4 explicit-defaults-for-timestamp=1 [client] default-character-set=utf8mb4③ project/docker/db/data
ディレクトリです。
⑤にて、/var/lib/mysql にマウントします。
/var/lib/mysql は、MySQLのデータディレクトリとなります。
(Dockerを停止しても消えないように)④ project/docker/db/initdb.d
こちらもディレクトリです。
⑤にて、/docker-entrypoint-initdb.d にマウントします。
現状、何も置いておりませんが、/docker-entrypoint-initdb.d にSQLやスクリプトを置くことで、初期データを設定可能です。
(そのうち使うかもということで用意しています)⑤ project/docker/docker-compose.yml
Dockerコンテナの起動オプションを記述するファイルです。
project/docker/docker-compose.ymlservices: web: build: ./web/ volumes: - ./web/ini/php.ini:/usr/local/etc/php/php.ini - ./web/conf.d/000-default.conf:/etc/apache2/sites-available/000-default.conf - ../laravel:/var/www/laravel ports: - 80:80 db: build: ./db/ environment: MYSQL_DATABASE: laravel_db MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: rootpassword volumes: - ./db/initdb.d:/docker-entrypoint-initdb.d - ./db/conf.d:/etc/mysql/conf.d - ./db/data:/var/lib/mysql ports: - "3306:3306"以下、簡単ですが説明です。
- build:Dockerfileのあるディレクトリパスの指定
- environment:環境変数の指定(ここでは、MySQLに必要なものを定義)
- volumes:マウントの指定(ホスト:コンテナ)
- ports:ポートの指定(ホスト:コンテナ)
⑥ project/docker/web/Dockerfile
①と同様、Dockerコンテナの構成内容を記述します。
ここでは、Dockerイメージとして、PHPを指定しています。
また、RUNで必要なモジュールを追加しています。project/docker/web/DockerfileFROM php:7.3-apache RUN set -x && \ pecl install xdebug && \ docker-php-ext-enable xdebug && \ a2enmod rewrite && \ docker-php-ext-install pdo_mysql
- xdebug:PHPStormでリモートデバッグしたかったので追加
- rewrite:laravelの認証機能を追加した時、上手く動かなかったので追加
⑦ project/docker/web/conf.d/000-default.conf
Apacheの設定ファイルです。
⑤にて、/etc/apache2/sites-available/000-default.conf にマウントします。
Laravelの公開フォルダは、public のため、DocumentRoot を /var/www/laravel/public としています。
(laravelは、⑤で /var/www/laravel にマウントしています)project/docker/web/conf.d/000-default.conf<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/laravel/public ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>⑧ project/docker/web/ini/php.ini
PHPの設定ファイルです。
⑤にて、/usr/local/etc/php/php.ini にマウントします。
ここでは、xdebugの設定を行なっています。project/docker/web/ini/php.ini; xdebug zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so xdebug.remote_enable = On xdebug.remote_autostart = On xdebug.remote_connect_back = Off xdebug.remote_host = docker.for.mac.localhost⑨ project/laravel
project直下で、以下のコマンドを投入すると、laravelディレクトリが作成されます。
中には、プロジェクト一式揃っています。$ composer create-project laravel/laravel --prefer-dist※ composerの導入は割愛します。
Dockerの起動
project/docker配下で実施します。まずは、buildから。
$ docker-compose build Building web Step 1/2 : FROM php:7.3-apache ---> 59d2cf691156 Step 2/2 : RUN set -x && pecl install xdebug && docker-php-ext-enable xdebug && a2enmod rewrite && docker-php-ext-install pdo_mysql ---> Using cache ---> bc81175279b3 Successfully built bc81175279b3 Successfully tagged docker_web:latest Building db Step 1/2 : FROM mysql:5.7 ---> 7452c4ea4f17 Step 2/2 : RUN touch /var/log/mysql/mysqld.log ---> Using cache ---> 3c43b21359e9 Successfully built 3c43b21359e9 Successfully tagged docker_db:latest次に起動します。
$ docker-compose up -d Creating docker_db_1 ... done Creating docker_web_1 ... done念の為、起動していることを確認します。
$ docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------- docker_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp docker_web_1 docker-php-entrypoint apac ... Up 0.0.0.0:80->80/tcpブラウザから
http://localhost
にアクセスすると、laravelの画面が表示されます。最後に
ここでは書いていないですが、この環境にLaravelの認証機能を追加してみたところ、ユーザ追加が出来ました。
MySQLにも追加したユーザのデータがありましたので、DBアクセスも問題なさそうです。
- 投稿日:2019-07-19T02:42:30+09:00
0からAWSでLAMPとLaravel環境構築(Windows)
手順
1.AWSアカウントを作成。
参照:AWS アカウント作成の流れ2.EC2というAmazonのクラウド上の仮想サーバーを構築。
参照:AWS EC2でWebサーバーを構築してみる3.LAMP環境を構築。
参照:チュートリアル: Amazon Linux 2 に LAMP ウェブサーバーをインストールする4.Laravelをインストール。
参照:AWSのEC2を立ち上げてLaravelのログイン機能を動かすまで
AWSでLaravelを立ち上げた1.AWSアカウントを作成
AWS は Amazon Web Services の略で、Amazon のクラウドサーバーを使用できるサービスです。
一年間無料でいろんな機能を試せます。
アカウントの登録は参照(AWS アカウント作成の流れ)に沿って行えばすぐできます。2.EC2構築
AWSにログインすると最初はこの画面が表示されると思います。
右上の地域はリージョンといい、自分の所在地に合わせて選択します。これは利用するデータセンターの場所を意味します。理論上近いほどレスポンスタイムが短いので、近いところを選びましょう。自分の場合は「東京」です。そしたら、左上のサービスからEC2を選択。
左のメニューの「インスタンス」 → 「インスタンス作成」を選択
一番目のAmazon Linux2 AMIを選択。
無料利用枠のt2.microにチェックを入れ、
他の設定は特にいじらずセキュリティグループの設定まで飛ばします。「新しいセキュリティグループを作成する」を選択し、「セキュリティグループ名と「説明」を好きなように入力し、画像のように五つのタイプを追加します。「ソース」のところでIP指定ができます。「任意の場所」を選択するとどこでもアクセスすることができ、「マイIP」を選択すると自分が現在使用しているネットワーク環境のIPでしかアクセスできなくなります。趣味程度の個人利用でしたら任意の場所で問題ありません。
右下の「確認と作成」 → 「起動」を押してから、このように表示されます。「新しいキーペアの作成」でキーペア名を入力。重要ですが、キーペアのダウンロードは必ずしてください。サーバーにアクセスするために必要となります。
「インスタンスの作成」 → 「インスタンスの表示」を順番に進めると、インスタントの画面に戻ります。
インスタンスの状態が running になっていれば作成成功です。
プラスα(オプション)
今作ったインスタンスに固定IPを割り当てることができます。左のメニューから「Elastic IP
」 → 「新しいアドレスの割り当て」 → 「割り当て」 → 「閉じる」で固定IPを一つゲットします。リストからIPを右クリック → 「アドレスの関連付け」で作成したインスタンスを選択し結びつけれます。3.LAMP環境の構築
①インスタンスに接続
サーバーに接続するため、ssh接続できるターミナルTeraTermをダウンロードします。インスタンス画面下の説明から固定IPとっていれば「IPv4 パブリック IP」、とっていなければ「パブリック DNS (IPv4)」をTeraTermのホストに入力して「OK」します。
次にユーザー名に「ec2-user」、秘密鍵に先ほどインスタンスを作るときにダウンロードしたキーペアファイルをセットして「OK」。
サーバーに接続できました。
直接とは関係ないですがコマンドでsudoを打つかどうかについて「root権限で`sudo`を付けた場合と付けない場合の違いに`su`は何の略?」を読めばわかると思います。②EC2のタイムゾーン設定
「Amazon EC2のタイムゾーンを日本時間に変更する方法」でわかりやすく書かれていますが、いくつか補足があります。
/etc/sysconfig/clockにはこのように変更すると書いてありますが、# ZONE="UTC" ZONE="Japan" UTC=true
trueのところをfalseにしないと再起動するときにタイムゾーンがUTCに戻ることがあります。# ZONE="UTC" ZONE="Japan" UTC=flaseここでルート権限を持たないため、
vimで保存するときにきっとこのようなエラーが出ると思います。E45: 'readonly' option is set (add ! to override)この解決法として自分がrootになるか、「[vim]read only のファイルをsudoで強制的に保存する」を参照してください。
オプションとして、「AWSの初期設定でrootパスワードを設定する」。一行目の
sshなんちゃらはすでにTeraTermログイン時にできてますので無視。
lnのオプションの意味は【 ln 】コマンド――ファイルのハードリンクとシンボリックリンクを作るに書いてあります。③LAMP環境構築
AWSの公式チュートリアル「チュートリアル: Amazon Linux 2 に LAMP ウェブサーバーをインストールする」の順序を追えばできます。自分はSQLに慣れているため、オプションの phpMyAdmin のインストールはしていません。phpMyAdmin はデータベースをGUIで管理できるツールです。
4.Laravelのインストール
①Composerをダウンロード
Composerについては「PHP開発でComposerを使わないなんてありえない!基礎編」。
以下ダウンロードコマンドです。$ curl -sS https://getcomposer.org/installer | sudo php $ sudo mv composer.phar /usr/local/bin/composerこれで
composer.pharというファイルが/usr/local/bin/composer/の下に置かれます。
このcomposer.pharファイルをcomposerというコマンドで実行できたら便利なので、composerというコマンドを作ります。alias composer='php /usr/local/bin/composer/composer.phar'ただし、これだけだと再起動するとリセットされて
composerが効かなくなりますので、常に成立するようにルートに存在する.bashrcというファイルに書き込みます。$ cd ~ # ルートに移動 $ ls -la # .bashrcがあるかどうかを確認 $ vi .bashrc # 「alias composer='php /usr/local/bin/composer/composer.phar'」を書き込むそしたらターミナルが起動すると読み込まれる
.bash_profileに.bashrcを参照するようにします。$ vi .bash_profile # 「source ~/.bashrc」を一番下に書き込む②拡張ライブラリをダウンロード
Laravelをダウンロードするのに必要なライブラリーは3つあります。
mbstring、mysqlndとxmlです。$ sudo yum install -y php-mbstring php-mysqlnd php-xml③Laravelをインストール
Laravel をインストールするディレクトリに移動します。自分の場合は
/var/www/の下にしました。$ cd /var/www $ composer create-project --prefer-dist laravel/laravel自分の場合ここで「proc_open(): fork failed errors」というエラーが出ました。「[PHP]Composer使用時に「proc_open(): fork failed errors」エラーが出た時の対処法」を見て解決できたので共有します。
-prefer-distって何ぞやと知りたい方には「composer の–prefer-distってよく使うけど何してる?」へ。④Apacheのドキュメントルートの設定と.htaccessの有効化
$ sudo vi /etc/httpd/conf.d/custom.confに
custom.conf# ドキュメントルート DocumentRoot "/var/www/laravel/public" # .htaccess 有効化 <Directory /var/www/laravel/public> AllowOverride All </Directory>を加えます。
そしたらApacheを再起動してください。$ sudo service httpd restart⑤パーミッションを変更
自分はパーミッションについてまだちんぷんかんぷんで、どの権限をどうすればいいか自分ではわかっていないので、他の方のブログを見たほうがいいかもしれません。基本的にパーミッションが合ってないとシステムにこのファイルに書き込めないよと怒られます。どうやらLaravelの場合は
storageとbootstrapの権限を変更する必要があるらしい。$ cd ~ $ sudo groupadd www $ sudo usermod -a -G www ec2-user $ exit一度ログアウトして再度入り直して、
$ cd /var/www $ sudo chmod -R 777 laravel/storage $ sudo chmod -R 775 laravel/bootstrap/cache $ sudo chown -R root:www /var/wwwこれでLaravelが使えるようになったはず。
- 投稿日:2019-07-19T00:16:28+09:00
Laravel-Excel(Maatwebsite/Excel)CSVの解釈の検証
Laravel-Excel のCSVの解釈の検証
Laravel-Excel(maatwebsite/excel) のcsvインポートの際のcsvの記述の仕方による値の解釈がどうなるのか検証を行いました。検証は下記の
DummyImportクラスインスタンスをExcelファサードのtoArray()の引数として渡し、取得した行の配列の値の解釈を確認します。app/Import/DummyImport.php<?php namespace App\Import; use Maatwebsite\Excel\Concerns\ToModel; use Excel; class DummyImport implements ToModel { public function model(array $row) { return $row; } } //DummyImportインスタンスをExcelファサードの`toArray()`の第一引数として渡す。 //併せて、対象csvファイルへのパスを第二引数として渡す。 $data = Excel::toArray(new DummyImport(), $filepath);検証1:文字リテラルの解釈
case1.csv"a","b","c" a,b,cクオーテーション
""を付けない時、付ける時の違いがあるのか検証しました。tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { /** @test */ public function CSV検証_文字列クオーテーションありなし() { $data = Excel::toArray(new DummyImport(), base_path().'/case1.csv'); $this->assertEquals(2, \count($data[0])); //クオーテーションあり $this->assertEquals(3, \count($data[0][0])); $this->assertEquals('a', $data[0][0][0]); $this->assertEquals('b', $data[0][0][1]); $this->assertEquals('c', $data[0][0][2]); //クオーテーションなし $this->assertEquals(3, \count($data[0][1])); $this->assertEquals('a', $data[0][1][0]); $this->assertEquals('b', $data[0][1][1]); $this->assertEquals('c', $data[0][1][2]); } }テスト結果.txtTime: 5.22 seconds, Memory: 16.00 MB OK (1 test, 9 assertions)違いはないようでした。
検証2:カンマ入り文字列の解釈
文字列にカンマの入った
a,aという文字列をインポートする場合はどうなるのか検証してみましたcase2.csv"a,a","b","c" a,a,b,c "a,a",b,c1列目はクオーテーション
""をすべての値に付けました。2列目はクオーテーション""を付けません。(おそらくこれを3カラムと解釈されない。)3列目はa,aにだけクオーテーションを付けました。tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { protected $extractedData; public function setUp():void { parent::setUp(); $this->extractedData = Excel::toArray(new DummyImport(), base_path().'/case2.csv'); } /** 中略 */ /** @test */ public function CSV検証_1列目_すべての値にクオーテーションを付ける() { $data = $this->extractedData; //1列目のカラム数は3であること $this->assertEquals(3, \count($data[0][0])); //値の検証 $this->assertEquals('a,a', $data[0][0][0]); $this->assertEquals('b', $data[0][0][1]); $this->assertEquals('c', $data[0][0][2]); } /** @test */ public function CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない() { $data = $this->extractedData; //2列目のカラム数は3であること $this->assertEquals(3, \count($data[0][1])); //値の検証 $this->assertEquals('a,a', $data[0][1][0]); $this->assertEquals('b', $data[0][1][1]); $this->assertEquals('c', $data[0][1][2]); } /** @test */ public function CSV検証_3列目_カンマありのデータにだけクオーテーションを付ける { $data = $this->extractedData; //カラム数は3であること $this->assertEquals(3, \count($data[0][2])); //値の検証 $this->assertEquals('a,a', $data[0][2][0]); $this->assertEquals('b', $data[0][2][1]); $this->assertEquals('c', $data[0][2][2]); } }テスト結果.txtFFF. 4 / 4 (100%) Time: 6.49 seconds, Memory: 16.00 MB There were 3 failures: 1) Tests\Unit\CSVExtractTest::CSV検証_1列目_すべての値にクオーテーションを付ける Failed asserting that 4 matches expected 3. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:23 2) Tests\Unit\CSVExtractTest::CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない Failed asserting that 4 matches expected 3. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:35 3) Tests\Unit\CSVExtractTest::CSV検証_3列目_カンマありのデータにだけクオーテーションを付ける Failed asserting that 4 matches expected 3. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:47 FAILURES! Tests: 4, Assertions: 12, Failures: 3.予想よりもエラーが多かったのですが、arrayのカラム数はファイル内最大のカラム数となるようでした。
カラム数のassertをコメントアウトして実行したところ、予想通り、取得される値は2列目が不正となり、1列目、3列目は有効でした。テスト結果.txtPHPUnit 7.5.13 by Sebastian Bergmann and contributors. .F.. 4 / 4 (100%) Time: 6.23 seconds, Memory: 16.00 MB There was 1 failure: 1) Tests\Unit\CSVExtractTest::CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'a,a' +'a' /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:37検証3:数値リテラル(整数、浮動小数点数)の検証
case3.csv1,-2147483648,2147483647 1.0,2.231224,00030141.213tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { /** 中略 */ public function CSV検証_整数、浮動小数点数() { $data = Excel::toArray(new DummyImport(), base_path().'/case3.csv'); $this->assertEquals(2, \count($data[0])); //整数 $this->assertEquals(3, \count($data[0][0])); $this->assertEquals(1, $data[0][0][0]); $this->assertEquals(-2147483648, $data[0][0][1]); $this->assertEquals(2147483647, $data[0][0][2]); //浮動小数点数 $this->assertEquals(3, \count($data[0][1])); $this->assertSame(1.0, $data[0][1][0]); $this->assertSame(2.231224, $data[0][1][1]); $this->assertSame(30141.213, $data[0][1][2]); } }テスト結果.txtPHPUnit 7.5.13 by Sebastian Bergmann and contributors. ...F 4 / 4 (100%) Time: 5.61 seconds, Memory: 16.00 MB There was 1 failure: 1) Tests\Unit\CSVExtractTest::CSV検証_整数、浮動小数点数 Failed asserting that '00030141.213' is identical to 30141.213. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:88 FAILURES! Tests: 4, Assertions: 24, Failures: 1.00030141.213は文字列として扱うようでした。
検証4:特殊文字を含む場合
エスケープで使うバックスラッシュ
\などを含んだ文字列でcsvファイルから値を取得します。case4.csv@#@!@$!#$,^^^^^32143()_----,\\++====51`5tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { /** 中略 */ /** @test */ public function CSV検証_特殊文字を含む場合() { $data = Excel::toArray(new DummyImport(), base_path().'/case4.csv'); $this->assertEquals(1, \count($data[0])); //整数 $this->assertEquals(3, \count($data[0][0])); $this->assertEquals('@#@!@$!#$', $data[0][0][0]); $this->assertEquals('^^^^^32143()_----', $data[0][0][1]); $this->assertEquals('\\\\++====51`5', $data[0][0][2]); } }テスト結果.txtPHPUnit 7.5.13 by Sebastian Bergmann and contributors. ..... 5 / 5 (100%) Time: 5.96 seconds, Memory: 16.00 MB OK (5 tests, 29 assertions)バックスラッシュ
\だけ、php側で、エスケープをちゃんとすることで検証できるようでした。参照
Laravel/Excelのインストール等に関しましては @rito328 さんのこちらのサイトに詳しく書いて頂いておりましたので参考にさせて頂きました。
https://www.ritolab.com/entry/160以上です。














