- 投稿日:2020-01-16T18:37:45+09:00
laravel のログイン機能name へ変更
以下の手順で上手く行きました。
1
【2014_10_12_000000_create_users_table.php】
$table->string('name')->unique();2
【LoginController.php】
public function username()
{
return 'name';
}3
【login.blade.php】
Name<div class="col-md-6"> <input id="name" type="name" class="form-control" name="name" value="{{ old('name') }}" required autofocus @if ($errors->has('name')) <span class="help-block"> <strong>{{ $errors->first('name') }}</strong> </span> @endif </div>拍手!
分かる人は分かる
- 投稿日:2020-01-16T18:37:45+09:00
laravel のログイン機能をnameでログインへ変更する機能
以下の手順で上手く行きました。
1
【2014_10_12_000000_create_users_table.php】
$table->string('name')->unique();2
【LoginController.php】
public function username()
{
return 'name';
}3
【login.blade.php】
Name<div class="col-md-6"> <input id="name" type="name" class="form-control" name="name" value="{{ old('name') }}" required autofocus @if ($errors->has('name')) <span class="help-block"> <strong>{{ $errors->first('name') }}</strong> </span> @endif </div>動作確認OK
拍手!
以上
- 投稿日:2020-01-16T17:38:08+09:00
Laravel で S3 にファイルを上げるタイミングで ACL を設定する
はじめに
Laravel のファイルストレージでは AWS の S3 を指定して保存することができます。
S3を指定する方法は公式ドキュメントを参照してもらうとして、保存は下記のようにstore
メソッドを利用します。<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class UserAvatarController extends Controller { public function update(Request $request) { $path = $request->file('avatar')->store('avatars'); return $path; } }重要なポイント
保存をするとき、上記の例では Storage ファサードを使っていません。
もちろんファサードを使って保存することも可能で、$path = Storage::putFile('avatars', $request->file('avatar'));このように公式ドキュメントには書いてあります。
で、やりたいのはドキュメントにファイル視認性
と書かれていますが、$visibility = Storage::getVisibility('file.jpg'); Storage::setVisibility('file.jpg', 'public')ファイルが既に保存されている場合、上記の設定でズバッと設定をしてしまいたい。デフォルトで private になっているところを公開の public にしたい場合はどうしたら良いのか、です。
つまりstore
の段階で最初からできてくれよってことですね。で、例の如く...
ないんですよね、ドキュメント上に正解が。
ヒントはあって、第二引数で他のディスク(この例だとローカルストレージを利用中)に保存したい場合などは下記のように書かれています。
$path = $request->file('avatar')->store( 'avatars/'.$request->user()->id, 's3' );となると、もしかすると第3や第4の引数でなにかあるかもしれない。
ということでコアを追いかけることになります。この場合の
$request
はIlluminate\Http\Request
です。
追跡していくと、Illuminate\Http\Request ↓ Illuminate\Http\Concerns\InteractsWithInput ↓ Illuminate\Http\UploadedFileと、辿れます。どうやって辿るかは正直、勘です。
エスパー並の感度で遡った結果、store メソッドを見つけました。
Illuminate\Http\UploadedFilepublic function store($path, $options = []) { return $this->storeAs($path, $this->hashName(), $this->parseOptions($options)); } public function storeAs($path, $name, $options = []) { $options = $this->parseOptions($options); $disk = Arr::pull($options, 'disk'); return Container::getInstance()->make(FilesystemFactory::class)->disk($disk)->putFileAs( $path, $this, $name, $options ); } protected function parseOptions($options) { if (is_string($options)) { $options = ['disk' => $options]; } return $options; }
parseOptions
を見ると、文字列を与えると自動的に配列でdisk
の key/val 型になるように整形してstoreAs
に渡しているのがみて取れますね。で、最終的には
putFileAs
で保存しているのが分かるわけですが、FilesystemFactory
でいよいよ Factory の文字が見えてまいりました。これの実体は
Illuminate\Contracts\Filesystem\Factory
です。
こいつは interface なので、基底にもつクラスがいるはずで、それは何かというとIlluminate\Filesystem\FilesystemAdapter
になります。
このなかにputFileAs
のメソッドも登場してくるわけですが、Illuminate\Filesystem\FilesystemAdapterpublic function putFileAs($path, $file, $name, $options = []) { $stream = fopen($file->getRealPath(), 'r'); $result = $this->put( $path = trim($path.'/'.$name, '/'), $stream, $options ); if (is_resource($stream)) { fclose($stream); } return $result ? $path : false; } public function put($path, $contents, $options = []) { $options = is_string($options) ? ['visibility' => $options] : (array) $options; if ($contents instanceof File || $contents instanceof UploadedFile) { return $this->putFile($path, $contents, $options); } return is_resource($contents) ? $this->driver->putStream($path, $contents, $options) : $this->driver->put($path, $contents, $options); }putFileAs は put への橋渡しをしていますね。
で、put のところでvisibility
が登場しており、この辺りがかなりそれっぽい。
で、最終的に$this->driver
で保存してそうだということが return からわかります。ここで使われている drive は当然ながら s3 のはずなので、driver を探します。
このファイルの先頭付近でuse League\Flysystem\AwsS3v3\AwsS3Adapter;と書かれているので、この辺りがとても怪しい。
本体は Laravel のコアから外れて/vendor/league
の下までいくとようやく出てきます。
このクラスを眺めていると、ようやく AWS SDK のオプションが出てきました。この辺は AWS SDK for PHP のドキュメントを見ると、ファイルアップロード関数の putObject と一致しているのがわかります。
League\Flysystem\AwsS3v3\AwsS3Adapterprotected static $metaOptions = [ 'ACL', 'CacheControl', 'ContentDisposition', 'ContentEncoding', 'ContentLength', 'ContentType', 'Expires', 'GrantFullControl', 'GrantRead', 'GrantReadACP', 'GrantWriteACP', 'Metadata', 'RequestPayer', 'SSECustomerAlgorithm', 'SSECustomerKey', 'SSECustomerKeyMD5', 'SSEKMSKeyId', 'ServerSideEncryption', 'StorageClass', 'Tagging', 'WebsiteRedirectLocation', ];この場合、ACL が今回の対象になるポイントで、Laravelがファイル視認性とか言ってますが、最終的に渡したいのは
private|public-read|public-read-write|authenticated-read|aws-exec-read|bucket-owner-read|bucket-owner-full-control
のどれかをこのアダプターの ACL というキーに突っ込みたいわけです。
というわけで、それっぽい関数をみてみると、League\Flysystem\AwsS3v3\AwsS3Adapterprotected function upload($path, $body, Config $config) { $key = $this->applyPathPrefix($path); $options = $this->getOptionsFromConfig($config); $acl = array_key_exists('ACL', $options) ? $options['ACL'] : 'private'; if (!$this->isOnlyDir($path)) { if ( ! isset($options['ContentType'])) { $options['ContentType'] = Util::guessMimeType($path, $body); } if ( ! isset($options['ContentLength'])) { $options['ContentLength'] = is_resource($body) ? Util::getStreamSize($body) : Util::contentSize($body); } if ($options['ContentLength'] === null) { unset($options['ContentLength']); } } try { $this->s3Client->upload($this->bucket, $key, $body, $acl, ['params' => $options]); } catch (S3MultipartUploadException $multipartUploadException) { return false; } return $this->normalizeResponse($options, $path); }upload のメソッドに
$acl = array_key_exists('ACL', $options) ? $options['ACL'] : 'private';
が出てきますね。
ACLという配列キーが出てこなければ private にせよ、と書いてあるので逆に ACL のキーで渡せば良いことがわかります。というわけで解決方法
長くなりましたが $options に配列で渡していけば良いことがわかりました。
$path = $request->file('avatar')->store('avatars', ['disk' => 's3', 'ACL' => 'public-read']);ということで、このように第二引数に配列で渡しましょう。その際に disk のキーを渡すのもお忘れなく。
- 投稿日:2020-01-16T16:53:31+09:00
Laravelで現在日時を指定できるプラグインを作った
Carbon
を正しく使っているプロジェクトに限るけど、現在日時を指定してアプリケーションを動かせるプラグインを作った。
スタンドアロンのサーバphp artisan serve
を1999年7月31日として実行したい場合は以下のように環境変数で日付を指定できる。$ LARAVEL_NOW=1999-7-31 php artisan serve
Carbon
がパースできる書式なら自由に指定できるので、日次バッチを昨日の日付で動かすこともできる。# 昨日の日付として動作確認できる! $ LARAVEL_NOW=yesterday php artisan app:daily-jobプラグインの中で
Carbon::setTestNow()
でセットしているだけ。動作確認するときにソースコードを変更せずに外部から指定できるので少し便利になった。
- 投稿日:2020-01-16T12:31:54+09:00
【Laravel】リレーション先で検索する方法
Laravelでリレーション先で検索することがあったため備忘録。
例えば下記のようなモデルがあったとします。
User.phpclass User extends Model { public function project() { return $this->belongsTo('App\Project'); } }Project.phpclass Project extends Model { public function organization() { return $this->belongsTo('App\Organization'); } }※主キーはidとします。
リレーション先で検索
Userからリレーション先であるProjectのorganization_idで絞り込みたいとします。
- whereHasを使用する場合
UserController.php$Users = User::whereHas('project', function ($query) use ($request) { $query->where('organization_id', $request->organization_id); })->get();
- whereHasを使用しない場合
UserController.php$Users = User::whereIn('project_id', function ($query) use ($request) { $query->from('projects') ->select('id') ->where('organization_id', $request->organization_id); })->get();リレーション先のリレーションで検索
Userからリレーション先であるProjectのリレーション先のOrganizationのnameで絞り込みたいとします。
- whereHasを使用する場合
UserController.php$Users = User::whereHas('project', function ($query) use ($request) { $query->whereHas('organization', function ($query) use ($request) { $query->where('name', $request->organization_name); } })->get();
- whereHasを使用しない場合
UserController.php$Users = User::whereIn('project_id', function ($query) use ($request) { $query->from('projects') ->select('id') ->whereIn('organization_id', function ($query) use ($request) { $query->from('organizations') ->select('id') ->where('name', $request->organization_name); }); })->get();
他により良い方法などありましたらご教示いただけますと幸いです。
- 投稿日:2020-01-16T01:00:17+09:00
material-ui-dropzoneでapplication/octet-streamのMime typeが登録できなかった話
内容
ずっと出来ると思っていたcadファイルをアップロードしようと思ってやってみたら、拒否されてしまったのでそれを解決したお話
結論
acceptedFilesのjwwみたいな感じで拡張子を指定してあげればうまく出来たよ
<DropzoneDialog open={open} onSave={handleSave.bind(this)} dialogTitle={"ファイルをアップロードする"} acceptedFiles={['image/*', 'application/*, .jww , .dwg , .dxf , .jwc , .p21']} dropzoneText={"アップロードしたいファイルをドラッグアンドドロップするかクリックして選択ください"} cancelButtonText={"アップロードをやめる"} submitButtonText={"アップロードする"} onDrop={handleCheck.bind(this)} showPreviews={true} maxFileSize={5242880} onClose={handleClose} />