- 投稿日:2020-07-10T22:29:02+09:00
Disable updating updated_at from Laravel Admin
Summary
If you'd like to stop updating updated_at column from Laravel Admin page, You can code like this
$form->model()->timestamps = false;Usage
app/Admin/Controllers/SomeController.php/** * Make a form builder. * * @return Form */ protected function form() { ... $form->saving(function (Form $form) { $form->model()->timestamps = false; }); return $form; }
- 投稿日:2020-07-10T18:14:25+09:00
laravel(npm)で追加したjsモジュールを外部のjsで使う
laravelはnpmによるjavascriptのモジュールのパッケージングを利用できるが
ソース修正の度にnpm run dev(prod)
でコンパイルしなければならないし
画面毎のjsファイルなどを配置したい場合などファイルが複数になる場合、
パッケージングを分けることはできるが、管理がめんどいので外部jsを呼べるようにする。
layouts/app.blade.php
に@yield('inc-javascript')
を追加
あと、jsの読み込みはすべてdeferをつける。layouts/app.blade.php<html> ... <head> ... <!-- Scripts --> <script src="{{ asset('js/app.js') }}" defer></script> @yield('inc-javascript') ... </head>各ページのbladeファイルで
@section('inc-javascript')
でjsファイルを指定するindex.blade.php@extends('layouts.app') @section('inc-javascript') <script src="{{ asset('/js/hogehoge.js') }}" defer></script> ... @endsectionapp.js内のモジュールをを使う
resources/js/bootstrap.js
でrequireする。
必要ならグローバル変数に格納する。bootstrap.jsrequire('moment'); globals.moment = require('moment'); window.moment = require('moment'); var moment = require('moment');
npm run dev(prod)
でpublic/js/app.js
にパッケージされる。
- 投稿日:2020-07-10T17:46:24+09:00
【Laravel】レイアウトの作成
書籍のアウトプットとして
Bladeには例アンツを継承してテンプレをセクションとして組み合わせてレイアウトを作成する機能がある。
レイアウトの作成
レイアウトの定義と継承
多くのページがあるサイトでは共通したデザインが表示される。
サイト全体を統一したデザインでレイアウトするためにBladeには継承とセクションがある。継承とは
PHPのクラスの継承と同じ。
既存のテンプレを継承して新しいテンプレを作ることセクションとは
継承でページをデザインするとき、ページ内の要素として活用されてるもの。
@secsionと@yield
セクション利用のための2つのディレクティブ
@section
レイアウトで様ざなま区画を定義する。
@section(名前) ...表示内容... @endsectionこれで指定した名前でセクションが用意される。
セクションは同じ名前の@yieldにはめ込まれ表示される。@yield
セクション内容をはめ込んで表示する。
@yield(名前)@yieldは記載場所を示すもので@endyieldはない。
ページレイアウトを作成する
例を見てみる。
resources/views/layoutでhelloapp.balde.phpを作成する。
そこに書いていくhelloapp.balde.php<html > <head> <title>@yield('title')</title> <style> body{ font-size:16pt;color:#999;margin:5px; } h1{ font-size:50px; text-align:right; color:#f6f6f6f6; margin:-20px 0px -30px 0px; letter-spacing:-4pt; } ul{ font-size:12pt; } hr{ margin:25px 100px; border-top:1px dashed #ddd; } .menutitle{ font-size:14px; font-weight:bold; margin:0px; } .content{ margin:10px; } .footer{ text-align:right; font-size:10pt; margin:10px; border-bottom:solid 1px #ccc; color:#ccc } </style> </head> <body> <h1>@yield('title')</h1> @section('menubar') <h2 class="menutitle">メニュー</h2> <ul> <li>@show</li> </ul> <hr size="1"> <div class="content"> @yield('content') </div> <div class="footer"> @yield('footer') </div> </body> </html>ここでいくつかのディレクティブが設定されている。
@section('menubar')これはメニュー表示の区画。
セクションは玖珂を定義するものだが、一番土台とアンルレイアウトで@sectionを用意する場合は。@endsectionではなく@showでセクションを終わりにする。
継承レイアウトの作成
index.balde.php@extends('layouts.helloapp') @section('title','Index') @section('menubar') @parent インデックスページ @endsection @section('content') <p>ここが本文のコンテンツ</p> <p>必要なだけ記述ができる</p> @endsection @section('footer') copyright 2020 tuyano. @endsectionHTMLらしくない表記になった。
@extendsについて
@extends('layouts.helloapp')layoutsフォルダのhelloapp.blade.indexファイルをロードし、親レイアウトとして継承する。
@sectionの書き方
2つの方法がある。
単純に表示させるだけ
@section('title','Index')'title'という名前のセクションに'Index'というテキスト値を設定。
@endsectionを併用した書き方
@section('menubar') @parent インデックスページ @endsection親レイアウトに'menubar'という@yieldがあればそこにはめ込まれて表示されるわけだが、
親レイアウトに'menubar'という@yieldはなく、@sectionがある。
この場合@sectionは上書きされる。@parentは親レイアウトのセクションを示す。
@sectionの上書きがされるとき、親のセクションも残したい場合は@parentで親のセクションをはめ込んで表示できる。これで表示してみるとhelloapp.blade.phpに、index.blade.phpに用意したセクションがはめ込まれて表示されていることが確認できる。
このようにレイアウトを継承するkとで子にはセクションに表示する内容だけを書けばいいことになり、お暗示レイアウトでページが表示される。
コンポ−ネントについて
継承を利用することで全体を同じデザインにすることができるが、時には一部を切り離したいこともある。
コンポ−ネントは1つのテンプレとして独立して用意されるレイアウト用の部品。
@componentディレクティブ
コンポーネントは普通のテンプレとして作成する。書き方に違いはない。
作成したコンポーネントは@componentで表示場所を設定できる。@component(名前) ...コンポ−ネネントの表示内容 @component名前はviewsフォルダのファイル名で指定される。
/views/components/ok.blade.php
ならcomponents.ok
で指定できる。コンポーネントを作成する
message.blade.php<style media="screen"> .message { border: double 4px #ccc; margin: 10px; padding: 10px; background-color: #fafafa; } .msg_title { margin: 10px 20px; color: #999; font-size: 16pt; font-weight: bold; } .msg_content { margin: 10px 20px; color: #aaa; font-size: 12pt; } </style> <div class="message"> <p class="mes_title">{{$msg_title}}</p> <p class="msg_content">{{$msg_content}}</p> </div>コンポーネントを読み込む
messageコンポーネントをテンプレにに読み込んで表示する。
@section('content')の部分を修正index.blade.php@section('content') <p>ここが本文のコンテンツ</p> <p>必要なだけ記述できる</p> @component('components.message') @slot('msg_title') CAUTION! @endslot @slot('msg_content') これはメッセージの表示 @endslot @endcomponent @endsectionスロットについて
\$msg_titleや\$msg_contentに値を送っているのがスロット
{{}}で指定した変数に値を設定する。@slot(名前) ...設定する内容 #endslot
- 投稿日:2020-07-10T16:07:39+09:00
LaravelのGateでロール毎に権限を分ける
今回設定するrole
今回はレベル0が管理者でなんでも出来るユーザー。あとは1-4まで分けようと思います。
調査の段階なので、管理者と一般ユーザーとしてレベル4が分かれているのを確認できれば良しとします。
ちなみにプロジェクト名はappとしています。各ファイルのパスの最初に出てくるところがプロジェクトの名前になってますね。開発環境
Laradockです。
PHP 7.4, MySQL 8.0, Laravel 6 で実行
構築は以下の手順で実施。
バージョンはそれぞれ自分が使いたい環境に合わせる。
https://qiita.com/ryuseino/items/e0e3a77245635b7cc101カラム追加用のマイグレーションファイルを作成
今回はユーザーテーブルにroleを追加して、それを使ってアクセス出来るページを制御してみます。
まずはファイルを作成。php artisan make:migration add_column_role_users_table --table=users出来たファイル編集
app/database/migrations/2020_07_08_103224_add_column_role_users_table.phppublic function up() { Schema::table('users', function (Blueprint $table) { $table->tinyInteger('role')->default(4)->after('password')->index('index_role')->comment('ロール'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('role'); }); }ファイル編集が終わったらmigrate実行してカラムを追加しておきます。
php artisan migrate既存のファイルの編集
今回は管理者のみが見れるadmin-onlyと一般ユーザーでも見れるuser-higherを追加。
app/app/Providers/AuthServiceProvider.phpprotected $policies = [ 'App\Model' => 'App\Policies\ModelPolicy', ]; /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); // adminに許可 Gate::define('admin-only', function ($user) { return ($user->role == 0); }); // 一般ユーザに許可 Gate::define('user-higher', function ($user) { return ($user->role <= 5); }); }admin用のページ作成
今回は通常のHomeを複製してからファイル名やクラス名、読み込むviewなど変更します。
作ったファイルのパスは以下。中身は省略。基本的にhomeとなってたところをadminにしただけです。
viewの方は表示される文字列を変えておくと分かりやすくていいかも知れません。app/app/Http/Controllers/AdminController.php
app/resources/views/admin.blade.php管理者だけ見れる文字列をテンプレートに追加
ページ毎の制御ではなく、ページの内容も分けることが出来ます。
今回はHomeの方で管理者だけに表示されるメッセージを追加。app/resources/views/home.blade.php@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">Dashboard</div> <div class="card-body"> @if (session('status')) <div class="alert alert-success" role="alert"> {{ session('status') }} </div> @endif You are logged in! @can('admin-only') <div class="alert alert-dark" role="alert"> 管理者だけですよ </div> @endcan </div> </div> </div> </div> </div> @endsection
@can
と@endcan
の間が管理者のみ表示されるメッセージですね。ユーザーのroleを設定して確認
2つユーザー登録し、roleを片方は0(管理者)にして、もう片方は4(デフォルトのユーザーレベル)に設定。
その後それぞれのユーザーでログインします。localhost/home にアクセスした場合
一般ユーザー -> デフォルトのホーム画面が出る
管理者 -> 追加で管理者用の文字列が出るlocalhost/admin にアクセスした場合
一般ユーザー -> アクセス出来ない (403の画面)
管理者 -> アクセス出来る参考にしたページ
以下のページが大変分かりやすかったです。
https://www.ritolab.com/entry/56こちらはもう少し細かいところも書いてありますね。
https://readouble.com/laravel/6.x/ja/authorization.html
- 投稿日:2020-07-10T14:46:13+09:00
Laravel ログイン時に処理を加える。
Laravel 5.5
PHP 7ログインと同時に処理を行いたいと思い、
調べたのでここに記したいと思います。vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.phpに
ログイン処理のリダイレクト直前で実行される authenticated() メソッドが書かれていますが、
何も設定されていません。vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php/** * The user has been authenticated. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function authenticated(Request $request, $user) { // }これをオーバーライドする形で処理を実装します。
LoginContorollerに処理を実装します。
例、
user情報のtypeが0の人がログインした場合
typeを20に設定するという処理を追加。Auth/LoginController.phpuse App\User; protected function authenticated(\Illuminate\Http\Request $request, $user) { if ($user->authority == 0) { $user->authority = 20; $user->save(); }$requestには、ログイン画面で入力した、メールアドレス(又は、ユーザーネーム)とパスワードが代入されています。
$userには、Userテーブルのユーザー情報が代入されています(ログインユーザーの情報)。
※この変数名は固定です。仮にcustomerテーブルにユーザー情報を保存していたとしてもデータは、$userに代入されます。
- 投稿日:2020-07-10T10:27:09+09:00
Laravel ビューファイルで作成する画面にYoutubeの動画を埋め込む
目的
- Youtubeの再生画面をLaravelのビューファイルに埋め込む方法をまとめる。
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提条件
- 実施環境のLaravelアプリ動作環境が構築できていること。
前提情報
- 特になし
読後感
- Laravelのビューファイルを用いた画面の表示にYoutubeの再生ウインドウを埋め込むことができる。
概要
- 埋め込みリンクのコピー
- ビューファイルの記載
詳細
- 投稿日:2020-07-10T10:00:34+09:00
Laravel クエリビルダを駆使する
目的
- クエリビルダを用いたDBのデータ取得方法とテーブル結合を用いたデータん取得方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提環境
- 先に記載した実施環境が構築されていること。
- 実施環境にて何かしらのLaravelアプリが作成されていること。
- Laravelアプリ用のDBが作成され.envファイルに必要情報が記載され、マイグレーションなどが行えること。
前提情報
- contentsテーブルとstatusesテーブルを新たに作成し、テーブル内に格納されているデータをクエリビルダを用いて取得する。
- コードの解説は本記事の下部の「ミニ解説」にてちょっとだけ解説している。
読後感
- contentsテーブルの内容をクエリビルダを用いて取得する。
- contentsテーブルとstatusesテーブルを結合し内容をクエリビルダを用いて取得する。
クエリビルダとは?
- LaravelのDBアクセスの手法の一つである。
- クエリ文を先に組み立ててからDBにアクセスする方法である。
- 使用する句はSQLと共通であるが記載方法に若干のクセがある。
概要
- contentテーブルの作成
- statusesテーブルの作成
- ルーティングの記載
- コントローラの作成と記載(クエリビルダの記載)
- ビューの作成と記載
- データの格納
- クエリビルダ単体の確認
- JOIN句の確認
詳細
contentテーブルの作成
アプリ名ディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを作成する。
$ php artisan make:model Content --migrationアプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。
$ vi database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php開いたマイグレーションファイルを下記の様に追記修正する。
アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateContentsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('contents', function (Blueprint $table) { $table->id(); //下記を追記 $table->string('content'); $table->integer('status_id'); //上記までを追記 $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('contents'); } }アプリ名ディレクトリで下記コマンドをジックしてマイグレーションを実行する。
$ php artisan migratestatusesテーブルの作成
アプリ名ディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを作成する。
$ php artisan make:model Status --migrationアプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。
$ vi database/migrations/YYYY_MM_DD_XXXXXX_create_statuses_table.php開いたマイグレーションファイルを下記の様に追記修正する。
アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_contents_table.php<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateContentsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('contents', function (Blueprint $table) { $table->id(); //下記を追記 $table->string('status_name'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('contents'); } }アプリ名ディレクトリで下記コマンドをジックしてマイグレーションを実行する。
$ php artisan migrateルーティングの記載
アプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。
$ vi routes/web.php下記の一行を追記する。
アプリ名ディレクトリ/routes/web.phpRoute::get('/output', 'ContentController@output');コントローラの作成と記載(クエリビルダの記載)
アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。
$ php artisan make:controller ContentControllerアプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。
$ vi app/Http/Controllers/Controller.php下記の様にoutputという名前のアクションを追加する。
アプリ名ディレクトリ/app/Http/Controllers/Controller.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; //下記を追記 use App\Content; class ContentController extends Controller { //下記を追記 public function output() { $contents_query = Content::select('*'); $contents = $contents_query->get(); return view('contents.output', [ 'contents' => $contents, ]); } //上記までを追記 }ビューの作成と記載
アプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。
$ mkdir resources/views/contentsアプリ名ディレクトリで下記コマンドを実行してビューファイルを作成して開く。
$ vi resources/views/contents/output.blade.phpビューファイルに下記を記載する。
アプリ名ディレクトリ/resources/views/contents/output.blade.php@foreach ($contents as $content) <hr> <p>{{$content['content']}}</p> <p>{{$content['status']}}</p> @endforeachデータの格納
アプリ名ディレクトリで下記コマンドを実行してtinkerを開く。
$ php artisan tinkertinkerにて下記を実行してcontentsテーブルにデータを追加する。
use App\Content; $a = new Content(); $a->content = 'test'; $a->status_id = 1; $a->save();tinkerにて下記を実行してstatusesテーブルにデータを追加する。
use App\Status; $b = new Status(); $b->status_name = 'good' $b->save(); $c = new Status(); $c->status_name = 'bad' $c->save();クエリビルダ単体の確認
アプリ名ディレクトリで下記コマンドを実行しローカルサーバを起動する。
$ php artisan serve下記にアクセスし、ブラウザから当該アプリを確認する。
下記の様にブラウザで表示されることを確認する。
JOIN句の確認
アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。
$ vi app/Http/Controllers/Controller.php開いたコントローラファイルのoutputアクション内部を下記の様に修正する。
アプリ名ディレクトリ/app/Http/Controllers/Controller.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Content; class ContentController extends Controller { public function output() { $contents_query = Content::select('*'); //下記を追記 $contents_query->join('statuses', 'contents.status_id', '=', 'statuses.id'); $contents = $contents_query->get(); return view('contents.output', [ 'contents' => $contents, ]); } }アプリ名ディレクトリで下記コマンドを実行してビューファイルを開く。
$ vi resources/views/contents/output.blade.phpビューファイルに下記を下記の様に修正する。
アプリ名ディレクトリ/resources/views/contents/output.blade.php@foreach ($contents as $content) <hr> <p>{{$content['content']}}</p> <!-- 下記を追記 --> <p>{{$content['status_name']}}</p> @endforeach下記にアクセスし、ブラウザから当該アプリを確認する。
下記の様にブラウザで表示されることを確認する。
ミニ解説
「クエリビルダ単体の確認」のアクション内のコードについて
下記にコントローラのアクションのコードを記載する。
アプリ名ディレクトリ/app/Http/Controllers/Controller.phppublic function output() { //DBにアクセスするためのクエリ文を組み立てている //Contentというモデルファイルに紐づいたテーブルの全てのカラムを取得する(SQL文のselect *と同じ)クエリ文を変数$contents_queryに格納している $contents_query = Content::select('*'); //先に組み立てたクエリ文を実行して取得したデータを変数$contentsに格納している。 $contents = $contents_query->get(); return view('contents.output', [ 'contents' => $contents, ]); }「JOIN句の確認」のアクション内のコードについて
下記にコントローラのアクションのコードを記載する。
アプリ名ディレクトリ/app/Http/Controllers/Controller.phppublic function output() { //DBにアクセスするためのクエリ文を組み立てている //Contentというモデルファイルに紐づいたテーブルの全てのカラムを取得する(SQL文のselect *と同じ)クエリ文を変数$contents_queryに格納している $contents_query = Content::select('*'); //テーブルの結合を行う //クエリ文が格納されている変数->join('結合するテーブル名', '結合元テーブル名.結合するカラム名', '=', '結合先テーブル名.リンクするカラム名') $contents_query->join('statuses', 'contents.status_id', '=', 'statuses.id'); //先に組み立てたクエリ文を実行して取得したデータを変数$contentsに格納している。 $contents = $contents_query->get(); return view('contents.output', [ 'contents' => $contents, ]); }
- 投稿日:2020-07-10T04:35:45+09:00
docker-compose.ymlのbuild設定はとりあえずcontextもdockerfileも埋めとけって話
docker-composeを使った開発では以下の2つのディレクトリ構成になっていることが多いです。
サービスディレクトリ直下にDockerfile. ├ app │ ├ Dockerfile │ └ ...その他ファイル群 ├ api │ ├ Dockerfile │ └ ...その他ファイル群 ├ nginx │ ├ Dockerfile │ └ ...その他ファイル群 └ docker-compose.ymldockerディレクトリ下にサービス毎にDockerfile. ├ app/ ├ api/ ├ nginx/ ├ docker │ ├ app │ │ └ Dockerfile │ ├ api │ │ └ Dockerfile │ └ nginx │ └ Dockerfile └ docker-compose.ymlDockerの コンテキスト という概念を知っていないと、ディレクトリ構成が違うだけで何度もコンテキスト周りのエラーで悩まされることがあります(1敗)。
なので自分的結論を出してみました。TL;DR
docker-compose を使った開発では
docker-compose.ymlversion: "3" services: nginx: build: ./docker/nginx/のようにDockerfileがあるディレクトリを指定するだけでなく
docker-compose.ymlservices: nginx: build: context: . dockerfile: ./docker/nginx/Dockerfileのようにコンテキストをルートディレクトリに指定して、Dockerfileの場所も直接指定しておけばおk
Dockerの「コンテキスト」とは?
docker build コマンドを実行したときの、カレントなワーキングディレクトリのことを ビルドコンテキスト(build context)と呼びます。 デフォルトで Dockerfile は、カレントなワーキングディレクトリにあるものとみなされます。 ただしファイルフラグ(-f)を使って別のディレクトリとすることもできます。 Dockerfile が実際にどこにあったとしても、カレントディレクトリ配下にあるファイルやディレクトリの内容がすべて、ビルドコンテキストとして Docker デーモンに送られることになります。
これをさらに要約すれば 「docker buildコマンドを実行した場所」ってことですね。
docker build
コマンドを実行した場所ってことなので、docker build
コマンドはDockerfileがあるディレクトリで実行すれば問題なさそうですね。しかし、
docker-compose
コマンドを使って開発している場合はどうでしょうか?
Dockerfileがあるディレクトリでコマンドを実行することってほとんど無いと思います。その場合はコンテキストについてどう考えればいいのでしょうか?サービス直下にDockerfileを置く場合
例として「Laravel, Nginx」というよくあるプロジェクトの構成で考えてみます。
ディレクトリ構成は以下の様になります。. ├ api │ ├ Dockerfile │ ├ app │ ├ bootstrap │ └ ...その他のLaravelファイル ├ nginx │ ├ Dockerfile │ └ default.conf └ docker-compose.ymlこのディレクトリ構成の場合、
api/Dockerfile
とnginx/Dockerfile
のコンテキストはそれぞれどこになるか分かりますか?
docker build
コマンドを実行するapi/
、nginx/
ディレクトリ?
nginx/
ディレクトリがコンテキストだとするとnginx/Dockerfile
は以下のようになります。nginx/DockerfileFROM nginx:1.18-alpine ADD ./default.conf /etc/nginx/conf.d/default.conf RUN mkdir -p /var/www/public ADD ../api/public /var/www/public以下の1文に注目してください。コンテキストが
nginx/
なのに、../api/public
で分かる通り、コンテキストのディレクトリから外れたファイルを参照していますね。nginx/DockerfileADD ../api/public /var/www/publicこのまま実行すると
ERROR: Service 'php' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder115741816/api: no such file or directoryのようなエラーが出ます。
Dockerはコンテキスト(カレントディレクトリ)の外のファイルにはアクセスできない仕様なのです。そこら辺に関しては以下の記事で詳しく説明されています。
https://qiita.com/toshihirock/items/c85f3eb5f4752b15ca3d
ではどうやって
nginx/
のコンテキストからapi/
のファイルにアクセスすればいいのでしょうか?
答えは簡単です。コンテキストをルートディレクトリにすればいいのです
docker-compose.yml
で「コンテキスト」と「Dockerfileのある場所」を直接指定してみましょう。docker-compose.ym;version: "3" services: nginx: build: context: . dockerfile: ./nginx/Dockerfile ports: - 8080:80 depends_on: - php php: build: context: . dockerfile: ./api/Dockerfile ports: - 9000:9000コンテキストはどちらのサービスも
build: context: .で
docker-compose.yml
があるルートディレクトリに設定。Dockerfileの場所は
dockerfile: ./nginx/Dockerfile dockerfile: ./api/Dockerfileでそれぞれ指定。
dockerディレクトリにDockerfileをまとめた場合
では次に
docker
というディレクトリを作って、その中に各サービスのDockerfileをまとめた構成を考えてみます。. ├ api │ └ Laravelのファイル群 ├ nginx │ └ default.conf ├ docker │ ├ php │ │ └ Dockerfile │ └ nginx │ └ Dockerfile └ docker-compose.yml先ほどと同様にコンテキストを
docker/php
やdocker/nginx
と考えた場合、どうやってもうまくいきません。
このディレクトリ構成の場合は、そもそもDockerfileからコンテキスト外のサービスのファイル群が入っているapi/
とnginx/
に一切アクセスできません。ここでも同様
docker-compose.yml
でコンテキストをルートディレクトリに、Dockerfileの位置も直接指定する必要がありそうです。docker-commpose.ymlversion: "3" services: nginx: build: context: . dockerfile: ./docker/nginx/Dockerfile ports: - 8080:80 depends_on: - php php: build: context: . dockerfile: ./docker/api/Dockerfile ports: - 9000:9000注意点
ルートディレクトリをDockerのコンテキストにすることで、Dockerfileはどんなファイルにもアクセスできるようになりました。
一方で、build
時はその分Dockerデーモンという奴にそれだけ多くのファイルを送ることになるので遅くなることがあるようです。
- 投稿日:2020-07-10T00:43:26+09:00
データプロバイダでテストに値を入れる
phpunitのデータプロバイダについての基本的な使い方のメモです。
PHPUnit 用のテストの書き方データプロバイダとは
同じアサーションで値だけ変えたい場合にデータプロバイダを使うと便利です。
テストに値を与える部分を別のメソッドに切り出すことができます。データプロバイダの配列の中身が引数としてテストメソッドに渡され、メソッド内の配列の分だけアサーションが反復処理されます。
下の例ではassertSame()が4回呼ばれることになります。
<?php use PHPUnit\Framework\TestCase; class DataTest extends TestCase { /** * @dataProvider additionProvider */ public function testAdd($a, $b, $expected) { $this->assertSame($expected, $a + $b); } public function additionProvider() { return [ [0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 3] ]; } }@dataProviderアノテーションでデータプロバイダメソッドを指定します。
/** * @dataProvider additionProvider */
データプロバイダーの返り値は配列にする必要があります。
return [ [0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 3] ];各データセットに名前を付ける
データセットには名前を付けることができます。テストに失敗した場合、データセットの名前が表示されるため、どのデータで失敗したのかわかりやすくなります。
<?php use PHPUnit\Framework\TestCase; class DataTest extends TestCase { /** * @dataProvider additionProvider */ public function testAdd($a, $b, $expected) { $this->assertSame($expected, $a + $b); } public function additionProvider() { return [ 'adding zeros' => [0, 0, 0], 'zero plus one' => [0, 1, 1], 'one plus zero' => [1, 0, 1], 'one plus one' => [1, 1, 3] ]; } }$ phpunit DataTest PHPUnit 4.6.0 by Sebastian Bergmann and contributors. ...F Time: 0 seconds, Memory: 5.75Mb There was 1 failure: 1) DataTest::testAdd with data set "one plus one" (1, 1, 3) Failed asserting that 2 is identical to 3. /home/sb/DataTest.php:9 FAILURES! Tests: 4, Assertions: 4, Failures: 1.