- 投稿日:2020-06-01T20:44:03+09:00
laravelでマルチドメイン対応
laravelプロジェクトでマルチドメイン対応の備忘録
概要:アンケートページのドメインとそれ以外のドメインで分けたい。
マルチドメインとは
一つのサーバーで複数のドメインを管理する運営方法。
メリット:複数のドメインを一つのサーバーで管理できるのは楽。サーバー費用が削減できる
https://sakuramarina.com/episode_11/やり方の概要
① .envファイルにドメインを設定する
② config/app.phpでドメイン名を定義
③ ミドルウェアの作成
④ app/Http/kernel.phpでミドルウェアの登録
⑤ web.phpでrouteをミドルウェアごとにまとめる1.envファイルにドメインを設定する
どこでもいいので、ドメインを設定します。
今回はステージングの環境なのでlocalの値です。.envMAIN_DOMAIN=127.0.0.1 SURVEY_DOMAIN=localhost2.ドメインを定義する
app.phpreturn [ 'main' => env('MAIN_DOMAIN', '127.0.0.1'), 'survey' => env('SURVEY_DOMAIN', 'localhost'), ]3.ミドルウェアの作成
ミドルウェアとはリクエストをコントローラに渡す前のクッションのようなものと認識しています
https://codezine.jp/article/detail/11643ミドルウェアの作成は以下のコマンド
php artisan make:middleware Survey
app.phpのsurveyキーは
app.survey
request()->getHost()
現在のURLのドメインを取得できる
https://stackoverflow.com/questions/39835650/how-do-you-get-the-http-host-with-laravel-5
現在のドメインがlocalhost以外だったら403を返す。Middleware/Survey.php<?php namespace App\Http\Middleware; use Closure; class Survey { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if (config('app.survey') !== request()->getHost()) { return \abort(403); } return $next($request); } }現在のドメインが127.0.0.1以外だったら403を返す。
Middleware/Main.php<?php namespace App\Http\Middleware; use Closure; class Main { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if(config('app.main') !== request()->getHost()) { return \abort(403); } return $next($request); } }.envの値はconfigを使ってあげる必要がある
https://hiroto-k.hatenablog.com/entry/2018/03/28/2130004.app/Http/kernel.phpでミドルウェアの登録
Kernel.phpprotected $routeMiddleware = [ 'domain.survey' => \App\Http\Middleware\Survey::class, 'domain.main' => \App\Http\Middleware\Main::class, ]5.web.phpでrouteをミドルウェアごとにまとめる
web.phpRoute::group(['middleware'=>['domain.main']],function() { //ここにmainで使用するルートを書く }); Route::group(['middleware'=>['domain.survey']],function() { //ここにsurveyで使用するルートを書く });詰まったところ
middlewareで期待した条件分岐にならなかったので、
var_dump(config('app.main'))
などとして中身を確認するとenvの値が反映されていなかった。app.mainはenvで設定したMAIN_DOMAIN=127.0.0.1なのに、中身は127.0.0.1:8000になっていた。最初envの設定は127.0.0.1:8000としていて途中で書き換えたが、環境変数はそのままキャッシュを持っていたためだった。
対応方法:envの値を反映させるためにphp artisan config:cacheを行った。
https://qiita.com/kawax/items/ea881a6c18b8d4e94d83ミドルウェアでテストを通してあげる場合
ミドルウェアにテスト環境でのロジックを書いていないので、このままではテストを行うと全て403で返ってきてしまします。
なので、if文に追加してあげます。Survey.phppublic function handle($request, Closure $next) { if ( config('app.survey') !== request()->getHost() && config('app.env') !== 'testing' //追加 ) { return \abort(403); } return $next($request); }Main.phppublic function handle($request, Closure $next) { if( config('app.main') !== request()->getHost() && config('app.env') !== 'testing' //追加 ) { return \abort(403); } return $next($request); }app.envはenvファイルで定義されています。
testingはvalue値phpunit.xml<php> <env name="APP_ENV" value="testing"> ///省略 </php>
- 投稿日:2020-06-01T19:28:09+09:00
【Laravel】php artisan migrateエラーへの対応 : 1 PDOException::("SQLSTATE[HY000] [2002] Connection refused") /Applications/MAMP/htdocs/task_test/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70
【Laravel】php artisan migrateエラーへの対応 : 1 PDOException::("SQLSTATE[HY000] [2002] Connection refused") /Applications/MAMP/htdocs/task_test/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70
上記エラーを対応した際の内容を記録します.
目次
動作環境
OS : macOS Mojave 10.14.6
MAMP : 5.7
MySQL : 5.7.26
PHP : 7.2.31
laravel : v6.18.16
解決法
先に解決した方法を記載します.
.envファイルにDB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock
を追加します..envDB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_blog DB_USERNAME=blog_user DB_PASSWORD=mnhgtr54 //追加 DB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sockキャッシュをクリアし、再度、マイグレーション
$ php artisan cache:clear #キャッシュをクリア $ php artisan migrate #再度実行 Migration table created successfully.こちらの記事を参考にしました.
https://teratail.com/questions/183824調べたこと
MAMPのページを見るとUnixソケットのパスが記載されている.
またUnixソケットを利用する場合はSocketを使用する必要があるとのこと
ここでそもそもUnixソケットとは何かについて調べたところUNIXドメインソケット通信という通信プロトコルということが分かった
UNIXドメインソケット(英: UNIX domain socket)とは、単一のオペレーティングシステム内で実行されるプロセス間でデータを交換するためのデータ通信の終点.UNIXドメインソケットは、アドレス・名前空間としてファイルシステムを使用している。これらは、ファイルシステム内のinodeとしてプロセスから参照される。これは、2つのプロセスが通信するために、同じソケットを開くことができる。しかし、コミュニケーションは、完全にオペレーティングシステムのカーネル内で発生する
エラー原因の考察
今回のエラーの件をまとめると
MacのターミナルとMAMPのMySQLは同一のマシン上にインストールされているため,
Unixドメインソケット通信を利用して接続する必要があった.そのため,MAMPのヘルプにあるようにドメインソケットのアドレスとなる
/Applications/MAMP/tmp/mysql/mysql.sock
を指定することでターミナルとMySQLで通信ができるようになった
- 投稿日:2020-06-01T17:32:50+09:00
Laravelのタスクスケジューラを使う
前提条件
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っていますLaravelでコマンドライン処理を行う
本記事は上記の内容を理解している前提で書かれていますCommandクラス作成
コマンドラインで
cd sample
php artisan make:command SampleSchedule
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Console/Commands/SampleSchedule.phpが現れますCommandクラス修正
さきほど作成したSampleSchedule.phpを下記に修正します
SampleSchedule.php<?php namespace App\Console\Commands; use Illuminate\Console\Command; class SampleSchedule extends Command { protected $signature = 'sample:name2 {arg1}'; protected $description = 'SampleSchedule'; public function __construct() { parent::__construct(); } public function handle() { $arg1 = $this->argument('arg1'); $this->line('arg1:' . $arg1); if ($arg1 === 'a') { return 1; } return 0; } }Commandクラス登録
/sample/app/Console/Kernel.php修正
Kernel.php‥‥ protected $commands = [ ‥‥ ,Commands\SampleSchedule::class ]; ‥‥Kernel.phpに定義されている$commands配列に先ほど作成したSampleScheduleクラス名を追記します
スケジュール作成
(1) /sample/app/Console/Kernel.phpに下記use文を追記
use Illuminate\Support\Facades\Log;
(2) /sample/app/Console/Kernel.phpのscheduleメソッドを修正します
Kernel.phpprotected function schedule(Schedule $schedule) { $schedule->command('sample:name2 0') ->everyMinute() ->appendOutputTo(dirname(dirname(dirname(__FILE__))) . '/storage/logs/SampleSchedule.log') ->onSuccess(function () { Log::info('成功'); }) ->onFailure(function () { Log::error('エラー'); }) ; $schedule->command('sample:name2 a') ->everyMinute() ->appendOutputTo(dirname(dirname(dirname(__FILE__))) . '/storage/logs/SampleSchedule.log') ->onSuccess(function () { Log::info('成功'); }) ->onFailure(function () { Log::error('エラー'); }); $schedule->command('sample:name2 z') ->dailyAt('10:00') ->appendOutputTo(dirname(dirname(dirname(__FILE__))) . '/storage/logs/SampleSchedule.log') ->onSuccess(function () { Log::info('成功'); }) ->onFailure(function () { Log::error('エラー'); }) ; }command関数は実行するコマンドクラスを指定します。引数はCommandクラスのsignature変数に定義した通りに書きます。php artisanコマンドでCommandクラスを実行するときと同じものになります[Laravelでコマンドライン処理を行う]。
everyMinute関数は毎分実行する指定になります
appendOutputTo関数はCommandクラスからの出力先を指定したファイルにするものです
onSuccess関数はCommandクラスから戻り値が0の場合に実行される処理を指定します。ただし、動作確認したLaravelバージョン7.1.1ではCommandクラスをバックグラウンド実行すると戻り値が0でもonSuccessが実行されないです。バックグラウンド実行はメソッドチェーンでrunInBackground関数を指定するとできるようになります。
onFailure関数はCommandクラスから戻り値が1の場合に実行される処理を指定します。ただし、動作確認したLaravelバージョン7.1.1ではCommandクラスをバックグラウンド実行すると戻り値が何であってもonFailureが実行されます。バックグラウンド実行はメソッドチェーンでrunInBackground関数を指定するとできるようになります。
dailyAt関数は毎日決まった時間にCommandクラスを実行する指定になります
everyMinute関数やdailyAt関数といった実行日時を指定する関数はいろいろ用意されています。下記で確認できます
Laravel 7.x タスクスケジュール 繰り返しのスケジュールオプション
動作確認
コマンドラインで
cd sample
php artisan schedule:run
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します/sample/storage/logs/SampleSchedule.logにSampleSchedule.phpからの出力が書き込まれています
/sample/storage/logs/laravel.logに/sample/app/Console/Kernel.phpのscheduleメソッド内にonSuccess、onFailureで指定したクロージャからの出力が書き込まれていますまた、
php artisan schedule:run
を実行したウインドウを見ると
php "artisan" sample:name2 0
php "artisan" sample:name2 a
が実行されたことがわかります
さらに、実行した時刻が10:00の場合、php "artisan" sample:name2 zも実行されているでしょうcron登録とスケジューラとしての使い方
先ほどコマンドラインで/sample/app/Console/Kernel.phpのscheduleメソッドを実行してみました
これをcronに指定します
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
/path-to-your-projectというのはご自身のLaravelプロジェクトへの絶対パスに書き換えてください
この記事であればsampleフォルダになります
このcronの設定を見ると分、時、日、月、曜すべてアスタリスクになっていることがわかります
これは1分に1回、要は毎分php artisan schedule:run実行されるという設定になります
つまり、毎分php artisan schedule:run
が実行されて、その際、実行日時に合うタスクスケジュール繰り返しのスケジュールオプションが設定されているcommandだけが実行されるという仕組みです先ほどコマンドラインで
php artisan schedule:run
を実行した際、everyMinute指定したものが実行されて(ちょうど10:00に実行しなければ)dailyAt指定したものは実行されなかったと思います
これはphp artisan schedule:runが毎分実行されるようにつくられているからです
- 投稿日:2020-06-01T16:24:08+09:00
【Laravel + GraphQL】Lighthouseを使ってみる【その1:チュートリアル】
Lighthouseの設計思想が何もわからん&そもそもディレクティブ全然わからん状態を脱却したいので、練習として公式のドキュメントを上から順番にやっていくことにしました。
環境
PHP: 7.2.5
Laravel: 7.0
Lighthouse: 4.13チュートリアル
デフォルトのスキーマを実行できるようにする
何はともかくインストールします。
composer require nuwave/lighthouseそうしたらまずはデフォルトのスキーマを試してみましょう。
php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schemaこのコマンドを実行すると以下のように
users
とuser
スキーマが生成されます。src/graphql/schema.graphql"A date string with format `Y-m-d`, e.g. `2011-05-23`." scalar Date @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date") "A datetime string with format `Y-m-d H:i:s`, e.g. `2018-05-23 13:43:32`." scalar DateTime @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTime") "A datetime and timezone string in ISO 8601 format `Y-m-dTH:i:sO`, e.g. `2020-04-20T13:53:12+02:00`." scalar DateTimeTz @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTimeTz") type Query { users: [User!]! @paginate(defaultCount: 10) user(id: ID @eq): User @find } type User { id: ID! name: String! email: String! created_at: DateTime! updated_at: DateTime! }スキーマが生成されたので適当にusersテーブルにデータを入れて以下のようにcurlを叩いてみましょう。
curl --request POST \ --url http://localhost:10080/graphql \ --header 'content-type: application/json' \ --data '{"query":"query {\n users {\n paginatorInfo {\n count\n currentPage\n }\n data {\n id\n name\n email\n created_at\n updated_at\n }\n }\n}"}'するとたったこれだけでデータベースの情報を取得することができました。
しかもペジネータも自動でついてます。{ "data": { "users": { "paginatorInfo": { "count": 1, "currentPage": 1 }, "data": [ { "id": "1", "name": "hgoe", "email": "hoge@example.com", "created_at": "2020-05-31 14:04:07", "updated_at": "2020-05-31 14:04:11" } ] } } }CORSの有効化
CORSを有効化するのを忘れないようにしましょう。
config/cors.phpreturn [ - 'paths' => ['api/*'], + 'paths' => ['api/*', 'graphql'], 'allowed_methods' => ['*'], 'allowed_origins' => explode(',', env('ALLOWED_CORS_ORIGINS', [])), ... ];開発用ツール
Lighthouseを便利に開発するために、公式ではGraphQL Playgroundの使用を推奨しています。
しかしこのツール、Dockerを使っているとめっちゃメモリ食ってまともに動かなくなることが稀によくあります。
なので個人的にはGraphQLをサポートしているInsomniaやAltair GraphQL Clientがおすすめです。
特にInsomniaは無料にも関わらず多彩な機能が搭載されており、とても便利なので現状使用している Rest Clientに不満がある方は是非とも触ってみることをおすすめします。
IDEサポート
Lighthouseでは独自定義されたディレクティブが多用されているようです。
なのでこれらをIntelliJ(PhpStrom)やVS Codeでも認識できるようにするために、IDEヘルパーを導入します。composer require --dev haydenpierce/class-finder php artisan lighthouse:ide-helperこれによって
schema-directives.graphql
と_lighthouse_ide_helper.php
が生成されるので、それぞれ.gitignore
に入れておきましょう。ディレクティブ
ここからはLighthouseの主機能となるディレクティブについて説明していきます。
基本的にLaravelのModelとGraphQLのオブジェクト(type)は一対一で自動でマッピングされます。
またtypeを定義する際は主キーに対応するフィールドにはid
という命名をすることが推奨されています。type User { id: ID! name: String! email: String! }@all
@allディレクティブはEloquentの
all()
と同じ役割をします。type Query { users: [User!]! @all }以下のようにスキーマを叩くと、以下のようにUserモデルに紐付けられているテーブル(今回はLaravelデフォルトのusersテーブル)の全ての情報が返ってきます。
query { user_all { id name email } }{ "data": { "users": [ {"id": "1", "name": "hoge", "email": "hoge@example.com"}, {"id": "2", "name": "fuga", "email": "fuga@example.com"} ] } }@paginate
paginateディレクティブは名前の通り、ペジネーションの役割を果たします。
type Query { users: [User!]! @paginate }例えば上記のpaginateディレクティブを付与したスキーマは内部的には自動で次のように変換されます。
type Query { users(first: Int!, page: Int): PostPaginator } type PostPaginator { data: [User!]! paginatorInfo: PaginatorInfo! }そして以下のように叩くことができるようになります。
{ users(first: 10) { data { id name } paginatorInfo { currentPage lastPage } } }またpaginatorには他にもいくつかの機能があります。
デフォルト数の指定
一度のリクエストで返すデフォルトのアイテム数をクエリ時に
count
引数で指定することなく、デフォルトで指定できるようになります。type Query { users: [User!]! @paginate(defaultCount: 10) }最大数の制限
ページ分割する際に要求できるアイテムの最大数を制限することができます。
type Query { users: [User!]! @paginate(maxCount: 10) }対象モデルの上書き
デフォルトではスキーマ定義で指定されたtypeと同じ名前のEloquentモデルを検索しますが、model引数を指定することでそれを上書きすることができます。
type Query { users: [User!]! @paginate(model: "App\\Models\\ActiveUser") }@find
findディレクションは渡された引数からモデル内を検索します。
Eloquentでいうwhereとfindですね。type Query { user(id: ID @eq): User @find }注意点として複数の結果が得られた場合例外が投げられるので、確実ではない場合は
@first
の使用が推奨されています。またこちらもpaginateと同様にmodelの上書きをすることが可能です。
type Query { user(id: ID @eq): User @find(model: "App\\Models\\ActiveUser") }@eq
Eloquentクエリに等号演算子を配置するディレクティブです。
以下の例だと引数のidの値がusersテーブルのidと一致するものを検索します。
type Query { user(id: ID @eq): User @find }また引数の名前がデータベースのカラム名と異なる場合は実際の列名を
key
に渡します。type Query { user(id: ID @eq(key: "user_id")): User @find }@create
新規のデータを登録するにはcreateディレクティブを使用することができます。
type Mutation { createUser(name: String!, email: String!, password: String!): User! @create }Mutation typeの中でスキーマを作成し、その引数に保存したいデータを指定するだけでデータベースに保存することができます。
mutation { createUser( name: "hogehoge" email: "hogehoge@example.com" password: "hogehoge" ) { id name email created_at updated_at } }ただし注意点として、作成や更新を許可するカラムに対してModelに
fillable
を指定する必要があります。(updateディレクティブに関しても同様)User.phpclass User extends Authenticatable { ... protected $fillable = [ 'name', 'email', 'password', ]; }またcreateディレクティブでも使用するmodelを変更することが可能です。
type Mutation { createUser(input: CreateUserInput! @spread): User! @create(model: "App\\Models\\ActiveUser") }独自のリクエスト型を定義する
特定のリクエスト型の定義は
input
を指定することで可能です。引数として単一のオブジェクトを使用する場合はリゾルバーに適応する前にネストした値を展開するように@spreadを使用する必要があります。
type Mutation { createUser(input: CreateUserInput! @spread): User! @create } input CreateUserInput { name: String! email: String! password: String! }@update
データの更新にはupdateディレクティブを使用します。
id
で指定されたデータに対して第二引数以降の値で更新します。type Mutation { updateUser(id: ID!, name: String, email: String): User @update }ちなみに動作的には引数を指定しないと更新されず、nullや空文字を送信するとそれぞれの値で上書きされます。
上書きされたくない場合はnot nullやバリデーションを設定するようにしましょう。またGraphQLでは一部のデータのみを更新するかをクライアント側が選択できるので、サーバ側ではオプションの引数を除く全ての引数を指定することが推奨されています。
もちろんupdateディレクティブでも独自のリクエスト型を定義して使用することが可能です。
type Mutation { updateUser(id: ID!, input: UpdateUserInput @spread): User @update } input UpdateUserInput { name: String email: String password: String }@upsert
upsertは
id
で指定されたデータが存在すればupdateし、なければ指定されたid
で新規にデータを作成します。
またid
が指定されていない場合は自動生成されたIDを使用してデータを作成します。type Mutation { upsertUser(id: ID!, name: String!, email: String!, password: String!): User @upsert }この時DB上でnot nullなカラムをGraphQLのスキーマ上でnullableにしても新規作成時にnullの値を入れてリクエストできてしまいますが、エラーになるので注意しましょう。(updateは問題なく動きます。)
@delete
deleteは
id
を指定するだけで簡単にデータを削除できる、ある意味危険なディレクティブです。type Mutation { deleteUser(id: ID!): User @delete }返り値は削除したデータがあればそれを返し、指定した
id
が対象となるデータがない場合はnullを返します。複数削除
複数データを一度に削除したい場合はIDをリストにします。
type Mutation { deleteUser(id: [ID!]!): [User!]! @delete }まとめ
今回は基本的なCRUD操作に必要なディレクティブについて学習しました。
自分でスキーマを定義していると返り値や引数周りの設計で悩むことが結構多かったのですが、そこらへんがサンプルで明示的に示されていてとても勉強になりました。ここまでやった感想としては複雑なビジネスロジックなどが必要のない簡単なアプリならSQLやModelなどを意識する必要がほとんどなく、ほとんどサーバの技術を触ったことがない人でもさっくり作れそうな印象を受けました。
流石に複雑なロジックを入れようとするとディレクティブだけでは難しいのでResolverを使っていくことになりますが、それでもペジネータなどが準備されているのは嬉しいですね。
(キャッシュ周りに関して把握してないので、どのようにデータを持つのかは気になりますが…)次回はResolverやリレーションなどについて調べていきたいと思います。
参考文献
- 投稿日:2020-06-01T12:10:19+09:00
Google Photos APIをPHPで使う
Google Photos APIを使用して、Google Photoにアクセスするアプリを作成しています。
その過程でのAPIを利用するまでを記載します。基本的にオフィシャルのリファレンスを参照していますが、そこから読み取りにくい部分などを具体的に紹介できたらと思っております。
Laravelを使用したコードを記載していますが、Laravelに特化した部分は少ないと思いますので、
Laravel以外のフレームワークを使っている場合もご参考になればと思います。準備
Laravelプロジェクト作成
$ composer create-project laravel/laravel googlephoto_sample --prefer-distGoogle Photos APIを有効にする
- Google APIsのダッシュボードからプロジェクト作成 → APIとサービスを有効化 → Google Photos APIを選択
- Google APIsのプロジェクトが作成済みなら Google Photos API このページから直接もできます
クライアントID作成
- Google APIsのダッシュボードから「認証情報」を選択 → 認証情報を作成 → OAuthクライアントID
- アプリケーションの種類は、ウェブアプリケーション
- 承認済みのリダイレクトURIは、今回は取り合えず http://localhost/photo/redirect
- 作成したクライアントIDの画面からJSONをダウンロード → credential.jsonにリネームしておく
- ダウンロードしたcredential.jsonをLaravelプロジェクトのフォルダに入れておきます。
Google APIs Client, Google Photos API ライブラリのインストール
composer.json"require": { "google/apiclient": "^2.0", "google/photos-library": "^1.5" },$ composer update
composer.jsonを編集せずに、直接コマンドラインかr
composer require google/apiclient:"^2.0"
みたいにやるとなぜか失敗します。Google Photos APIを使ってみる
PhotoControllerという名前のコントローラーと、コントローラーから呼び出されるGooglePhotoServiceという名前のクラスを作成していきます。
認証URLの生成、表示
app\Services\GooglePhotoService.php<?php namespace App\Services; use Google\Auth\Credentials\UserRefreshCredentials; use Google\Photos\Library\V1\PhotosLibraryClient; class GooglePhotoService { private function createGoogleClient() { $client = new \Google_Client(); $client->setApplicationName('GooglePhotoSample'); $client->setScopes(\Google_Service_PhotosLibrary::PHOTOSLIBRARY_READONLY); $client->setAuthConfig(base_path("credentials.json")); $client->setAccessType('offline'); return $client; } public function createAuthUrl($redirectUri) { $client = $this->createGoogleClient(); $client->setRedirectUri($redirectUri); return $client->createAuthUrl(); } }app\Http\Controllers\PhotoController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Services\GooglePhotoService; class PhotoController extends Controller { public function start() { $service = new GooglePhotoService(); $url = $service->createAuthUrl("http://localhost/photo/redirect"); return view(start, [ 'url' => $url ]); } }resources\views\start.blade.php<html> <body> <div class="flex-center position-ref full-height"> <div class="content"> Step.1<br/> <a href="{{$url}}">{{$url}}</a> </div> </div> </body> </html>routes\web.phpRoute::get('/photo/start, 'PhotoController@start);OAuthのリダイレクト先を作成
リダイレクト時に受け取ったauthCodeをもとにアクセストークンを取得する。
取得したアクセストークンを保存する処理は$saveTokenFunction
という名前のコールバック関数として定義する。app\Services\GooglePhotoService.phppublic $saveTokenFunction = null; public function getAccessToken($authCode) { $client = $this->createGoogleClient(); $accessToken = $client->fetchAccessTokenWithAuthCode($authCode); if ($this->saveTokenFunction != null) { call_user_func($this->saveTokenFunction, $accessToken); } return $accessToken; }app\Http\Controllers\PhotoController.phppublic function saveToken($accessToken) { // 保存の処理は省略。データベースなどに保存 } public function redirect(Request $request) { $authCode = $request->input('code'); $service = new GooglePhotoService(); $service->saveTokenFunction = [$this, 'saveToken']; $service->getAccessToken($authCode); return view('redirect', [ ]); }resources\views\redirect.blade.php// 省略
routes\web.phpRoute::get('/photo/redirect, 'PhotoController@redirect);PhotosLibraryClientを生成
取得したアクセストークンで、PhotosLibraryClientを生成
アクセストークンの期限が切れたときのリフレッシュの処理も一緒に実装app\Services\GooglePhotoService.phppublic function getPhotosLibraryClient($accessToken) { $client = $this->createGoogleClient(); $client->setAccessToken(json_decode($accessToken, true)); if ($client->isAccessTokenExpired()) { $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); if ($this->saveTokenFunction != null) { call_user_func($this->saveTokenFunction, $$client->getAccessToken()); } } $authCredentials = new UserRefreshCredentials(\Google_Service_PhotosLibrary::PHOTOSLIBRARY_READONLY, [ "client_id" => $client->getClientId(), "client_secret" => $client->getClientSecret(), "refresh_token" => $client->getRefreshToken() ]); return new PhotosLibraryClient(['credentials' => $authCredentials]); }PhotosLibraryClientを使用してGoogle Photoからアルバム情報を取得してみる
app\Http\Controllers\PhotoController.phppublic function listAlbums() { $accessToken = [] // 保存してあるアクセストークンを取得する処理 // 例) $accessToken = UserToken::where('user_id', auth()->user()->id)->value('token'); $service = new GooglePhotoService(); $service->saveTokenFunction = [$this, 'saveToken']; $client = $service->getPhotosLibraryClient($accessToken); $pagedResponse = $client->listAlbums(); $data = []; foreach ($pagedResponse->iterateAllElements() as $album) { $data[] = $album->getTitle(); } return response()->json([ "title" => $data ]); }routes\web.phpRoute::get('/photo/albums', 'PhotoController@listAlbums');以上です
authCodeからAccessTokenを取得する処理を、なんとかAPIだけで完結させたかったのですが
できませんでした。今回は、このような形でウェブページを一度経由してその後APIで利用するという形になりました。
- 投稿日:2020-06-01T12:08:28+09:00
Lravel MixでVue.js+Bootstrapの簡単なログインフォームを作る。
FIRST PLAN株式会社のフロントエンドエンジニアtakeです。
sampleText
さて、今回はテストでログインフォームを作ったので良ければご覧ください。
こんな事をやりました
環境設定
まずはVue.js。
今回はLaravel内で使っているので、LaravelでVue.jsを使えるようにするには以下のコマンドを実行します。$ composer require laravel/ui $ php artisan ui vue --authすぐにvueを始めたい場合は公式ドキュメントにある通りCDNでも使えますし、初めからwebpackの環境構築がされている「Vue CLI」もあるので活用してみてください。
ただ今回は環境設定の記事ではないのでそこら辺は割愛します。そして次にBootstrapですが、BootstrapVueを使用します。
機能は同じでBootstrapの記法もそのまま使えるのですが、jQuery依存だったコンポーネントがVueのディレクティブが使えるように拡張されています。$ npm install bootstrap-vue bootstrapでインストールし、
以下のコードをメインのjsファイルに追加します。import BootstrapVue from 'bootstrap-vue'; Vue.use(BootstrapVue);後は好みの問題なのですが、FontAwesomeとvue-sweetalert2をインストールします。
vue-sweetalert2もBootstrapVueと同じで機能は元のsweetalert2と変わりませんが、Vueでそちらを使うとアイコン部分で表示崩れが起きる事があるのでそれを修正したものになります。
Bootstrapと同様にこちらもインストールします。FontAwesome
$ npm install --save @fortawesome/fontawesome-freeimport '@fortawesome/fontawesome-free/css/all.css';vue-sweetalert2
$ import VueSweetalert2 from 'vue-sweetalert2';import 'sweetalert2/dist/sweetalert2.min.css'; Vue.use(VueSweetalert2);コード
html
今回は以下のような感じで、
card
とinput-group
を使って実装しました。HTML<template> <section class="login-form d-flex flex-solumn justify-content-center align-items-center w-100 text-center"> <div class="login-form__field card rounded-0 pt-5 pb-3"> <i class="login-form__budge fas fa-user-circle text-primary bg-white rounded-circle"></i> <div class="card-body"> <h1 class="login-form__heading card-title text-primary font-weight-bold mb-0">Sign in</h1> <hr class="bg-primary mt-0 mb-4"> <p class="card-text text-muted mb-4">ユーザー名とパスワードを入力してください。</p> <div class="input-group mx-auto mb-4"> <div class="input-group-prepend"> <span class="input-group-text bg-primary text-white" id="basic-addon1"> <i class="fas fa-user"></i> </span> </div> <input class="form-control" type="text" placeholder="Username" v-model="login.user_name"> </div> <div class="input-group mx-auto mb-4"> <div class="input-group-prepend"> <span class="input-group-text bg-primary text-white" id="basic-addon1"> <i class="fas fa-key"></i> </span> </div> <input class="form-control rouded-0" type="password" placeholder="Password" v-model="login.password"> </div> <button class="login-form__button btn btn-primary w-75 mb-4" type="button" :disabled="checkInput" @click="signIn">Login </button> <div class="login-form__attention d-flex justify-content-between my-o mx-auto"> <div class="custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input" id="remember-me" v-model="login.remember"> <label class="custom-control-label" for="remember-me">情報を記憶する</label> </div> <a class="card-link" href="#"> <u>パスワードを忘れた方はこちら</u> </a> </div> </div> </div> </section> </template>Scss
今回はBootstrapベースなので、BEMを採用して影のエフェクト以外は軽く整える程度にしました。
scss.login-form { &__field { position: relative; max-width: 30rem; //影エフェクト &:after { content: ''; position: absolute; bottom: 20px; right: 55px; z-index: -1; width: 50%; height: 100px; box-shadow: 100px 0 10px 15px rgba(0, 0, 0, .3); transform: skew(-40deg); } } //__field &__budge { position: absolute; top: -2rem; left: 50%; font-size: 6rem; transform: translateX(-50%); } //__budge &__attention { font-size: 0.6rem; } //__attention &__button { border-radius: 0!important; } //__button } // .login-formJavaScript
これがデフォルトのVueの記述方法になります。
ざっくり説明するとdata
は変数等を格納する場所・computed
は変更があるとリアルタイムで値を再計算してくれる場所・methods
は文字通りメソッドを格納する場所です。
他にもwatch
やライフサイクルフック等開発に便利な機能が色々とあるので、詳しくは公式ドキュメントをご参照ください。まず
data
内のlogin
は「ユーザーネーム・パスワード・ユーザー情報を記憶するか否か」を保持しています。
html内にv-model="login.user_name"
といった記述があると思いますが、このv-model
によって双方向データバインディングを実現しています。
これによりデータと表示の同期・DOM操作を自力でやる必要がなくなります。次は
computed
ですが、今回はlogin.user_name
とlogin.password
が条件に組み込まれていますが、どちらかの値が変更された段階で自動で値を更新します。
メソッド内にif (!this.checkInput)
と指定されている関数がありますが、このように使用する事で、他の場所で毎回入力を確認する必要がなくなります。最後に
methods
は一番簡単で、関数を格納する場所になります。
とりあえず確認用にv-model
で同期した値をsweetalert2で表示しています。JavaScriptexport default { data() { return { //ログイン情報 login: { user_name: '', password: '', remember: false } } }, computed: { //ユザーネームとパスワードの両者が入力されている事を判定する値、自動で変更を検知し反映してくれる checkInput() { return (!this.login.user_name || !this.login.password) ? true : false; } }, methods: { signIn() { //ユーザーネームとパスワードの両者が入力されていた時のみ発火する。 if (!this.checkInput) { //v-modelで同期した値を出力する this.$swal({ icon: 'info', title: 'Information', text: ` ID: ${this.login.user_name}, Password: ${this.login.password}, Remember: ${this.login.remember} ` }) } return; } //signIn } }最後に
$ npm run dev
でコンパイルして確認すると...
キチンと動いています。
よろしければ参考にしてみて下さい。
- 投稿日:2020-06-01T12:08:28+09:00
Laravel MixでVue.js+Bootstrapの簡単なログインフォームを作る。
FIRST PLAN株式会社のフロントエンドエンジニアtakeです。
sampleText
さて、今回はテストでログインフォームを作ったので良ければご覧ください。
こんな事をやりました
環境設定
まずはVue.js。
今回はLaravel内で使っているので、LaravelでVue.jsを使えるようにするには以下のコマンドを実行します。$ composer require laravel/ui $ php artisan ui vue --authすぐにvueを始めたい場合は公式ドキュメントにある通りCDNでも使えますし、初めからwebpackの環境構築がされている「Vue CLI」もあるので活用してみてください。
ただ今回は環境設定の記事ではないのでそこら辺は割愛します。そして次にBootstrapですが、BootstrapVueを使用します。
機能は同じでBootstrapの記法もそのまま使えるのですが、jQuery依存だったコンポーネントがVueのディレクティブが使えるように拡張されています。$ npm install bootstrap-vue bootstrapでインストールし、
以下のコードをメインのjsファイルに追加します。import BootstrapVue from 'bootstrap-vue'; Vue.use(BootstrapVue);後は好みの問題なのですが、FontAwesomeとvue-sweetalert2をインストールします。
vue-sweetalert2もBootstrapVueと同じで機能は元のsweetalert2と変わりませんが、Vueでそちらを使うとアイコン部分で表示崩れが起きる事があるのでそれを修正したものになります。
Bootstrapと同様にこちらもインストールします。FontAwesome
$ npm install --save @fortawesome/fontawesome-freeimport '@fortawesome/fontawesome-free/css/all.css';vue-sweetalert2
$ import VueSweetalert2 from 'vue-sweetalert2';import 'sweetalert2/dist/sweetalert2.min.css'; Vue.use(VueSweetalert2);コード
HTML
今回は以下のような感じで、
card
とinput-group
を使って実装しました。HTML<template> <section class="login-form d-flex flex-solumn justify-content-center align-items-center w-100 text-center"> <div class="login-form__field card rounded-0 pt-5 pb-3"> <i class="login-form__budge fas fa-user-circle text-primary bg-white rounded-circle"></i> <div class="card-body"> <h1 class="login-form__heading card-title text-primary font-weight-bold mb-0">Sign in</h1> <hr class="bg-primary mt-0 mb-4"> <p class="card-text text-muted mb-4">ユーザー名とパスワードを入力してください。</p> <div class="input-group mx-auto mb-4"> <div class="input-group-prepend"> <span class="input-group-text bg-primary text-white" id="basic-addon1"> <i class="fas fa-user"></i> </span> </div> <input class="form-control" type="text" placeholder="Username" v-model="login.user_name"> </div> <div class="input-group mx-auto mb-4"> <div class="input-group-prepend"> <span class="input-group-text bg-primary text-white" id="basic-addon1"> <i class="fas fa-key"></i> </span> </div> <input class="form-control rouded-0" type="password" placeholder="Password" v-model="login.password"> </div> <button class="login-form__button btn btn-primary w-75 mb-4" type="button" :disabled="checkInput" @click="signIn">Login </button> <div class="login-form__attention d-flex justify-content-between my-o mx-auto"> <div class="custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input" id="remember-me" v-model="login.remember"> <label class="custom-control-label" for="remember-me">情報を記憶する</label> </div> <a class="card-link" href="#"> <u>パスワードを忘れた方はこちら</u> </a> </div> </div> </div> </section> </template>CSS
飽くまでBootstrapベースなので、scssでBEMを採用して影のエフェクト以外は軽く整える程度にしました。
scss.login-form { &__field { position: relative; max-width: 30rem; //影エフェクト &:after { content: ''; position: absolute; bottom: 20px; right: 55px; z-index: -1; width: 50%; height: 100px; box-shadow: 100px 0 10px 15px rgba(0, 0, 0, .3); transform: skew(-40deg); } } //__field &__budge { position: absolute; top: -2rem; left: 50%; font-size: 6rem; transform: translateX(-50%); } //__budge &__attention { font-size: 0.6rem; } //__attention &__button { border-radius: 0!important; } //__button } // .login-formJavaScript
以下がデフォルトのVueの記述方法になります。
ざっくり説明すると
data
は変数等を格納する場所・computed
は変更があるとリアルタイムで値を再計算してくれる場所・methods
は文字通りメソッドを格納する場所です。
他にもwatch
やライフサイクルフック等開発に便利な機能が色々とあるので、詳しくは公式ドキュメントをご参照ください。さて、まず
data
内のlogin
は「ユーザーネーム・パスワード・ユーザー情報を記憶するか否か」を保持しています。
html内にv-model="login.user_name"
といった記述があると思いますが、このv-model
によって双方向データバインディングを実現しています。
どちらかが変更された段階でもう片方にも自動で変更が同期されるため、自分で逐一document.querySelector(element)~
をする必要がなくなります。次は
computed
ですが、今回はlogin.user_name
とlogin.password
が条件に組み込まれていますが、どちらかの値が変更された段階で自動で値を更新します。
メソッド内にif (!this.checkInput)
と指定されている関数がありますが、このように使用する事で他の場所で毎回入力を確認する必要がなくなります。
ちなみにbutton
にある:disabled="checkInput"
にも使用されていますが、まずこの:
マークはv-bind
といってhtml内の属性(class
やhref
等)に付ける事で内部でJavaScriptのコードを直接使用可能にするものです。
今回はこれらを利用してdisabled
の値をフォーム入力の有無によって動的に変更しています。最後に
methods
は一番簡単で、関数を格納する場所になります。
とりあえず確認用にv-model
で同期した値をsweetalert2で表示しています。
イベントハンドリングはhtml側で@event="hoge"
のように行います。(今回の場合は@click="signIn"
)
ちなみにこの@click
以下はコンパイル時に削除されるため、htmlを汚染する心配はありません。JavaScriptexport default { data() { return { //ログイン情報 login: { user_name: '', password: '', remember: false } } }, computed: { //ユーザーネームとパスワードの両者が入力されている事を判定する値、自動で変更を検知し反映してくれる checkInput() { return (!this.login.user_name || !this.login.password) ? true : false; } }, methods: { signIn() { //ユーザーネームとパスワードの両者が入力されていた時のみ発火する。 if (!this.checkInput) { //v-modelで同期した値を出力する this.$swal({ icon: 'info', title: 'Information', text: ` ID: ${this.login.user_name}, Password: ${this.login.password}, Remember: ${this.login.remember} ` }) } return; } //signIn } }最後に
$ npm run dev
でコンパイルして確認すると...
キチンと動いています。
よろしければ参考にしてみて下さい。
- 投稿日:2020-06-01T11:52:51+09:00
#MacでLaravelの環境構築をした件
MacでLaravelの環境構築をした件
MacでLaravelの環境構築をした際の内容をまとめます.
目次
動作環境
OS : macOS Mojave 10.14.6
HOMEBREW_VERSION: 2.2.17
Composer version 1.10.6
Laravel Installer 2.3.0
PHP : 7.2.31
構築手順
homebrewのインストール
Homebrewはmacのパッケージマネージャです。
パスワードを求められたらMacのログインパスワードを適宜入力してください$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"インストールが完了したらアップデートをして完了です.
$ brew upgrade
composerのインストール
brew install composer
インストールが完了したらPATHを追加し、インストールできているか確認します.
PATHの追加とバージョン確認$ echo export PATH=\"$HOME/.composer/vendor/bin:\$PATH\" >> ~/.bash_profile $ source .bash_profile $ composer -V Composer version 1.10.6 2020-05-06 10:28:10phpのインストール
PHPのバージョンを確認
$ php -v PHP 7.1.23 (cli) (built: Feb 22 2019 22:19:32) ( NTS )注意点
7.1系でLaravel newを行うと以下のエラーが出たため7.2以上をインストールします.
Your requirements could not be resolved to an installable set of packages. Problem 1 - This package requires php ^7.2.5 but your PHP version (7.1.23) does not satisfy that requirement.7.2系のインストール
brew install php@7.2
PATHの追加とバージョン確認$ echo 'export PATH="/usr/local/opt/php@7.2/bin:$PATH"' >> ~/.bash_profile $ echo 'export PATH="/usr/local/opt/php@7.2/sbin:$PATH"' >> ~/.bash_profile $ source ~/.bash_profile $ php -v PHP 7.2.31 (cli) (built: May 14 2020 10:55:21) ( NTS )laravelのインストール
laravelのインストール$ composer global require "laravel/installer"注意点
WEBサイトで以下のコマンドを書いていることがありましたが、このコマンドではエラーになります.詳細はこちらをご参考ください
誤$ composer global require “laravel/install”
動作確認
最後にアプリを作成するディレクトリに移動し実行
$ laravel new dg_laravel_test
サーバーを起動
$ php artisan serve Laravel development server started: http://127.0.0.1:8000 [Tue May 19 16:52:04 2020] 127.0.0.1:56892 [200]: /favicon.icoブラウザから
http://127.0.0.1:8000
にアクセス
以下の画面がでれば成功おわりに
今回の件で以下のことを学びました。
1. Mac OSでのLaravelの環境構築
- 投稿日:2020-06-01T04:15:51+09:00
ドメインの異なるサイトにAPIリクエストを送るとエラーが発生
ブラウザから違うドメインにAPIリクエストをした際に、以下のエラーが発生
Access to XMLHttpRequest at 'http://xxxxx' from origin 'http://localhost:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.原因
ドメインが違うサイトにリクエストを送る時、「あなたのサイトからのリクエストを許可していない」ときに起こるエラー
解決策は3つ
- リクエストを送りたいサイトに、自分のサイトのドメインからのリクエストを許可してもらう。
- Chromeの拡張機能 CORS Unblock を使ってリクエストを送れるようにする
- サーバサイド(Nodeやphpなど)からリクエストを送る。
実施した解決策
リクエストの送信先がLaravelで作っている自作APIだったので、1 の方法を実施。
具体的には、laravelに新しくCORSを許可するミドルウェアを作成して、router.php で該当のAPIリクエストにミドルウェアを適応することで解決。参考にしたサイト
- 投稿日:2020-06-01T04:15:51+09:00
【CORS】ドメインの異なるサイトにAPIリクエストを送るとエラーが発生
ブラウザから違うドメインにAPIリクエストをした際に、以下のエラーが発生
Access to XMLHttpRequest at 'http://xxxxx' from origin 'http://localhost:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.原因
ドメインが違うサイトにリクエストを送る時、クライアント(送信元のサイト)からのリクエストを許可していないときに起こるエラー
解決策は3つ
- リクエストを送りたいサイトに、自分のサイトのドメインからのリクエストを許可してもらう。
- Chromeの拡張機能 CORS Unblock を使ってリクエストを送れるようにする
- サーバサイド(Nodeやphpなど)からリクエストを送る。
実施した解決策
リクエストの送信先がLaravelで作っている自作APIだったので、1 の方法を実施。
具体的には、laravelに新しくCORSを許可するミドルウェアを作成して、router.php で該当のAPIリクエストにミドルウェアを適応することで解決。参考にしたサイト
- 投稿日:2020-06-01T04:15:51+09:00
【CORS】ドメインのことなるサイトにAPIリクエストを送るとエラーが発生
ブラウザから違うドメインにAPIリクエストをした際に、以下のエラーが発生
Access to XMLHttpRequest at 'http://xxxxx' from origin 'http://localhost:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.原因
ドメインが違うサイトにリクエストを送る時、「あなたのサイトからのリクエストを許可していない」ときに起こるエラー
解決策は3つ
- リクエストを送りたいサイトに、自分のサイトのドメインからのリクエストを許可してもらう。
- Chromeの拡張機能 CORS Unblock を使ってリクエストを送れるようにする
- サーバサイド(Nodeやphpなど)からリクエストを送る。
実施した解決策
リクエストの送信先がLaravelで作っている自作APIだったので、1 の方法を実施。
具体的には、laravelに新しくCORSを許可するミドルウェアを作成して、router.php で該当のAPIリクエストにミドルウェアを適応することで解決。参考にしたサイト
- 投稿日:2020-06-01T03:50:17+09:00
Laravelでコマンドライン処理を行う
前提条件
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っていますCommandクラス作成
コマンドラインで
cd sample
php artisan make:command SampleCommand
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Console/Commands/SampleCommand.phpが現れますCommandクラス修正
さきほど作成したSampleCommand.phpを下記に修正します
SampleCommand.php<?php namespace App\Console\Commands; use Illuminate\Console\Command; class SampleCommand extends Command { protected $signature = 'sample:name1 {arg1} {arg2=val2} {arg3?} {--option1} {--option2=} {--option3=opVal3} {--option4=*}'; protected $description = 'このプログラムの説明を書く'; public function __construct() { parent::__construct(); } public function handle() { $arg1 = $this->argument('arg1'); $arg2 = $this->argument('arg2'); $arg3 = $this->argument('arg3'); $option1 = $this->option('option1'); $option2 = $this->option('option2'); $option3 = $this->option('option3'); $option4 = $this->option('option4'); $this->line('下記入力を受け付けました'); $this->line('arg1:' . $arg1); $this->line('arg2:' . $arg2); $this->line('arg3:' . $arg3); $this->line('option1:' . $option1); $this->line('option2:' . $option2); $this->line('option3:' . $option3); $this->line('option4:' . var_export($option4, true)); $in = $this->ask('何か入力してください'); $this->line('下記入力を受け付けました'); $this->line($in); $in = $this->secret('何か入力してください。この入力中はユーザーがタイプした値を表示しません'); $this->line('下記入力を受け付けました'); $this->line($in); if ($this->confirm('yかyesを入力するとtrueとして扱います')) { $this->line('true'); } else { $this->line('false'); } $in = $this->choice( '選択入力。カンマ区切りで複数入力できます', ['php', 'Laravel', 'apache', 'eclipse'], //選択肢 $defaultIndex = 1, // 何も選ばれなかった場合に返ってくる選択肢の要素 $maxAttempts = 2, // 最大選択可能個数 $allowMultipleSelections = true // 複数選択可ならtrueにする ); $this->line('下記入力を受け付けました'); $this->line(var_export($in, true)); $this->line('テーブル出力'); $head = ['col1', 'col2', 'col3', 'col4']; $body = [ ['1-col1', '1-col2', '1-col3', '1-col4'], ['2-col1', '2-col2', '2-col3', '2-col4'], ['3-col1', '3-col2', '3-col3', '3-col4'], ]; $this->table($head, $body); $this->line('プログレスバー出力'); $bar = $this->output->createProgressBar(10); // プログレスバーを10の区切りで出力 $bar->start(); for ($i = 0; $i < 10; $i++) { sleep(1); $bar->advance(); } $bar->finish(); $this->line(''); $this->error('エラー出力'); } }
$signature
変数はこのコマンドの引数、オプションを定義します
ユーザーから入力してもらう引数とオプションはすべて波括弧で囲んで定義します
{arg1} 第1引数必須。プログラム内で$this->argument('arg1')
で値を取得できる
{arg2=val2} 第2引数任意。入力されなかった場合、$this->argument('arg2')
でval2が返る
{arg3?} 第3引数任意。デフォルト値無し
{--option1} オプション。option1オプションが指定されると$this->option('option1')
でtrueが返る
{--option2=} オプション。コマンド実行時何か値を与えるオプション
{--option3=opVal3} オプション。入力されなかった場合、$this->option('option3')
でopVal3が返る
{--option4=*} オプション。コマンド実行時何か値を与えるオプション。複数の値を渡すことができる。$this->option('option4')
の結果は配列となる
$description
変数はこのコマンドの説明ですhandleメソッドは実際の処理です
コマンドライン処理が実行されるとhandleメソッドが実行されます
$this->argument
は引数を取得できます
$this->option
はオプションを取得できます
$this->line
は文字列を出力できます
$this->ask
はユーザーからの入力を待ちます
$this->secret
はユーザーからの入力を待ちます。ただし、ユーザーのタイピングした値が表示されません。パスワード入力などに使います
$this->confirm
はユーザーの入力によりbool値を返します
$this->choice
はユーザーに選択肢から値を選択させます
$this->table
はテーブル形式で表示されます
$this->output->createProgressBar
の戻り値を使うことによってプログレスバーを表示できます
$this->error
でエラー時の文字列出力ができますCommandクラス登録
作成したCommandクラスを呼び出せるようにLaravelに登録しましょう
/sample/app/Console/Kernel.php修正Kernel.php‥‥ protected $commands = [ Commands\SampleCommand::class ]; ‥‥Kernel.phpに定義されている$commands配列に先ほど作成したSampleCommandクラス名を追記します
これでコマンドラインで実行できるようになりました動作確認
コマンドラインで
cd sample
php artisan sample:name1 aaa bbb ccc --option1 --option2=eee --option3=fff --option4=ggg --option4=hhh
先ほど作成したSampleCommandクラスの$signature
変数に定義した通りにコマンドラインで実行します
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します実行結果
下記入力を受け付けました arg1:aaa arg2:bbb arg3:ccc option1:1 option2:eee option3:fff option4:array ( 0 => 'ggg', 1 => 'hhh', ) 何か入力してください: > aaa 下記入力を受け付けました aaa 何か入力してください。この入力中はユーザーがタイプした値を表示しません: > 下記入力を受け付けました bbb yかyesを入力するとtrueとして扱います (yes/no) [no]: > y true 選択入力。カンマ区切りで複数入力できます [Laravel]: [0] php [1] Laravel [2] apache [3] eclipse > 2,3 下記入力を受け付けました array ( 0 => 'apache', 1 => 'eclipse', ) テーブル出力 +--------+--------+--------+--------+ | col1 | col2 | col3 | col4 | +--------+--------+--------+--------+ | 1-col1 | 1-col2 | 1-col3 | 1-col4 | | 2-col1 | 2-col2 | 2-col3 | 2-col4 | | 3-col1 | 3-col2 | 3-col3 | 3-col4 | +--------+--------+--------+--------+ プログレスバー出力 10/10 [============================] 100% エラー出力実行できました
- 投稿日:2020-06-01T00:34:10+09:00
Laravel + Vue.jsのかんたん実装
laravel上でVuejsを実装は、大まかに3段階です。
- resources/js/components にvueデータを作成。
- resources/js/app.jsにvueコンポーネントを定義。
- app.jsに定義したvueコンポーネントを resources/views/*.blade.phpにマークアップ。
ExampleComponent.vueを表示してみましょう!
app.jsを以下のように設定します。resources/js/app.jsrequire('./bootstrap'); window.Vue = require('vue'); Vue.component('example-component', require('./components/ExampleComponent.vue').default); const app = new Vue({ el: '#app', });デフォルトのwelcome.blade.phpに記述します。
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>ExampleComponent</title> <link rel="stylesheet" href="{{ asset('css/app.css') }}"> </head> <body> <div id="app"> <example-component></example-component> </div> <script src="{{ asset('js/app.js') }}"></script> </body> </html>vueファイルを記述、変更したらターミナルでコンパイルをします。
#コンパイル npm run dev #サーバーを立ち上げて確認 php artisan serve新しくVueを作成してみましょう。
1. vueファイルを作成します。
resources/js/components/LaravelVue.vue<template> <div> <h1>LaravelでVueを実装</h1> <p>Good!!</p> </div> </template>
- resources/js/app.jsにvueコンポーネントを定義します。
resources/js/app.jsrequire('./bootstrap'); window.Vue = require('vue'); Vue.component('example-component', require('./components/ExampleComponent.vue').default); Vue.component('laravelvue', require('./components/LaravelVue.vue').default); const app = new Vue({ el: '#app', });
- app.jsに定義したvueコンポーネントを resources/views/welcome.blade.phpにマークアップ。
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>laravelvue</title> <link rel="stylesheet" href="{{ asset('css/app.css') }}"> </head> <body> <div id="app"> <laravelvue></laravelvue> </div> <script src="{{ asset('js/app.js') }}"></script> </body> </html>コンパイルのたびに
npm run dev
するのは、面倒くさいので
vueファイルの記述が変更されるたびに自動でコンパイルしてくれるnpm run watch
を実行します。#コンパイル npm run watch
command + T
で新しくタブを作ってサーバーを立ち上げます。#サーバーを立ち上げて確認 php artisan serveもう一度vueファイルの記述を変更してみましょう。
resources/js/components/LaravelVue.vue<template> <div> <h1>LaravelでVueを実装できた!!</h1> <p>Yeah!!</p> </div> </template>
npm run watch
で監視されているので、vueファイルの記述に変更があると自動的にコンパイルをしてくれます。
ブラウザを更新してみましょう!
更新されています。かんたんでは、ありますが少しでも参考になれば幸いです。