Laravel ファイルアップロード時のコントローラーの書き方

普通にHTMLで書いた場合

<form action="/uploadfile" method="post" enctype="multipart/form-data">
	@csrf
	<div class="form-group">
		<input type="file" class="form-control-file" name="fileToUpload" id="exampleInputFile">
	</div>
	<button type="submit" class="btn btn-primary">Submit</button>
</form>

collectiveのForm::openのthird parameterに’files’=>trueを追加する
Form:file(‘file’)とする

{!! Form::open(['method'=>'POST', 'action'=>'PostsController@store', 'files'=>true]) !!}
		{{ csrf_field()}}

		<div class="form-group">
			{!! Form::file('file', ['class'=>'form-controll']) !!}
		</div>

		<div class="form-group">
			{!! Form::label('title', 'Title') !!}
			{!! Form::text('title', null, ['class'=>'form-controll']) !!}
		</div>

		<div class="form-group">
			{!! Form::submit('Create Post', ['class'=>'btn btn-primary']) !!}

		</div>
	{!! Form::close() !!}

controller

public function store(CreatePostRequest $request)
    {
        return $request->file('file');
    }

オリジナル名、ファイルサイズ

public function store(CreatePostRequest $request)
    {
        $file = $request->file('file');
        
        echo "<br>";
        echo $file->getClientOriginalName();

        echo "<br>";
        echo $file->getClientSize();
    }

$ php artisan make:migration add_path_column_to_posts –table=posts
migration file

public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $table->string('path');
        });
    }

public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $talbe->dropColumn('path');
        });
    }

$ php artisan migrate

Post.php

protected $fillable = [
		'user_id',
		'title',
		'content',
		'path'
	];

PostsController.php

public function store(CreatePostRequest $request)
    {

        $input = $request->all();

        if($file = $request->file('file')){
            $name = $file->getClientOriginalName();

            $file->move('./images', $name);

            $input['path'] = $name;

        }

        Post::create($input);
    }

view

<ul>
		@foreach($posts as $post)

		<div class-"image-container">
			<img height="100" src="images/{{$post->path}}">
		</div>
		<li><a href="{{ route('posts.show', $post->id) }}">{{$post->title}}</a></li>
		
		@endforeach
	</ul>

images/{{$post->path}} は、accessorsでimages/を省略する

Model:Post.php

public $directory = "/images/";

public function getPathAttribute($value){

		return $this->directory . $value;
	}

View: index.php

<div class-"image-container">
			<img height="100" src="{{$post->path}}">
		</div>

今回はシンプルな書き方で、ファイルに対する拡張子やファイルサイズのバリデーションをつけていませんが、コントローラーもしくはrequestsでバリデーションを付ければ良いでしょう。

ファイルの格納場所はサーバー内ですが、これをS3にする場合はmove()の箇所を変える必要があります。

Laravel QueryScopeのサンプル

Query Scopeはoperationのショートカット機能

e.g. latest

public function index()
    {
        $posts = Post::latest()->get();

        // return $posts;
        return view("posts.index", compact('posts'));
    }

order by created desc | ascと一緒です。

$posts = Post::orderBy('id', 'desc')->get();

qeuryScopeを自作する
Model: Post.php
public function static scope.${functionName}がコンベンション。${functionName}はcamelCaseで書く

public static function scopeLatest($query){
			return $query->orderBy('id', 'desc')->get();
	}

PostsController

public function index()
    {
        $posts = Post::latest();

        // return $posts;
        return view("posts.index", compact('posts'));
    }

queryのインクルード機能のようなものか。

Laravel Mutatorsの使い方

AccessorsはDBから呼び出す際に、modelでget.${ColumnName}.Attributeとしましたが、Mutatorは、DBに挿入する際に、set.${ColumnName}.Attributeで指定します。

Model: User.php

public function setNameAttribute($value){

        $this->attributes['name'] = strtoupper($value);

    }

Route

Route::get('/setname', function(){

	$user = User::find(1);

	$user->name = "william";

    $user->save();
});

mysql> select * from users;
+—-+———+————+———-+—————-+————+———————+————+
| id | name | email | password | remember_token | created_at | updated_at | country_id |
+—-+———+————+———-+—————-+————+———————+————+
| 1 | WILLIAM | john@gmail | 1234 | NULL | NULL | 2019-12-11 03:31:16 | 0 |
+—-+———+————+———-+—————-+————+———————+————+
1 row in set (0.00 sec)

getとsetは飽きるほどやりましたね。

Laravel Accessorsの使い方

> insert into users (name, email, password) values (‘john’, ‘john@gmail’, ‘1234’);

Route::get('/getname', function(){

	$user = User::find(1);

	echo $user->name;

});

Model:User.php

public function getNameAttribute($value){

        return ucfirst($value);
    }

Accessorにより、jonhがJohnと表示されます。
Modelのfunction nameは、get.${ColumnName}.Attribute がコンベンションです。

strtoupperにすると、JOHNとなります。

public function getNameAttribute($value){

        return strtoupper($value);
    }

名前は日本語だと用途は直ぐには思いつかないが、使い方を研究する余地はある。
ちなみに、DBのレコードの値は変わらない。呼び出すときにAccessorで変更している。

LaravelでCarbonを使いたい時

まず、phpの日付関数

Route::get('/dates', function(){
	$date = new DateTime('+1 week');

	echo $date->format('m-d-Y');
});

続いてCarbon
composerで探します
$ php composer.phar search carbon
nesbot/carbon A simple API extension for DateTime.
nesbot/carbon An API extension for DateTime that supports 281 different languages.

anyway, laravelはdefaultでcarbonはincludeされています。
use Carbon\Carbonでクラスを指定すれば、すぐに使えます。

carbon

use Carbon\Carbon;

Route::get('/dates', function(){
	$date = new DateTime('+1 week');

	echo $date->format('m-d-Y') . "<br>";

	echo Carbon::now();

	echo '<br>';
	echo Carbon::now()->addDays(10)->diffForHumans();

	echo '<br>';
	echo Carbon::now()->subMonths(5)->diffForHumans();

	echo '<br>';
	echo Carbon::now()->yesterday()->diffForHumans();

	echo '<br>';

});

laravelのform validation

PostsController

public function store(Request $request)
    {
        $this->validate($request, [
            'title'=> 'required',  
        ]);
        Post::create($request->all());
        return redirect('/posts');
    }

Route
※古い書き方

Route::group(['middleware'=>'web', function(){

	Route::resource('/posts', 'PostsController');

}]);

view: create
※古い書き方

@if(count($errors) > 0)
			<div class="alert alert-danger">
				<ul>
					@foreach($errors->all() as $error)

						<li>{{ @error }}</li>
					@endforeach
				</ul>

			</div>
		@endif

$ php artisan make:request CreatePostRequest
./app/Http/Request/CreatePostRequest.php

public function authorize()
    {
        return true;
    }

public function rules()
    {
        return [
            //
            'title' => "required"
        ];
    }

controller

public function store(CreatePostRequest $request)
    {
        $this->validate($request, [
            'title'=> 'required',  
        ]);
        Post::create($request->all());
        return redirect('/posts');
    }

バリデーションは実務で日常的に使うので、比較的馴染みやすいように思います。

laravel collectiveを使ってみよう

パッケージというと、centOSのrpmや、npmのnode moduleのようなイメージでしょうか?
「laravel illuminate/html」で検索します

github:https://github.com/illuminate/html

https://laravelcollective.com/docs/5.2/html
なんじゃこりゃーー

composer.json
requireにインストールするパッケージ名を追加します。

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.2.*",
        "laravelcollective/html":"^5.2.0"
    },

$ php composer.phar update

./config/app.php
provider

'providers' => [
    // ...
    Collective\Html\HtmlServiceProvider::class,
    // ...
  ],

aliases

'aliases' => [
 // ...
 'Form' => Collective\Html\FormFacade::class,
 'Html' => Collective\Html\HtmlFacade::class,
 // ...
],

あ、aliasesは普段使用しているclass名です
ここで引っ張て来てるんですね

view: create.blade.php
{!! Form::open() !!}と記載する

<h1>Create Post</h1>
	<!-- <form method="post" action="/posts"> -->
	{!! Form::open() !!}
		{{ csrf_field()}}
		<input type="text" name="title" placeholder="Enter tilte">
		<input type="submit" name="submit">
	</form>

methodを記入

{!! Form::open(['method'=>'POST', 'action'=>'PostsController@store']) !!}
		{{ csrf_field()}}
		<input type="text" name="title" placeholder="Enter tilte">
		<input type="submit" name="submit">
	{!! Form::close() !!}

更に、text form、submit buttonもcollectiveを使用

{!! Form::open(['method'=>'POST', 'action'=>'PostsController@store']) !!}
		{{ csrf_field()}}

		<div class="form-group">
			{!! Form::label('title', 'Title') !!}
			{!! Form::text('title', null, ['class'=>'form-controll']) !!}
		</div>

		<div class="form-group">
			{{ Form::submit('Create Post', ['class'=>'btn btn-primary'])}}

		</div>
	{!! Form::close() !!}

edit & delete

@section('content')

	<h1>Edit Posts</h1>
	{!! Form::model($post, ['method'=>'PATCH', 'action'=>['PostsController@update', $post->id]]) !!}
		{{ csrf_field()}}

		<div class="form-group">
		{!! Form::label('title', 'Title') !!}
		{!! Form::text('title', null, ['class'=>'form-controll']) !!}

		{!! Form::submit('Update Post', ['class'=>'btn btn-info']) !!}
		</div>
	{!! Form::close() !!}

	{!! Form::open(['method'=>'DELETE', 'action'=>['PostsController@destroy', $post->id]]) !!}
		{{ csrf_field()}}

		<div class="form-group">
		{!! Form::submit('DELETE', ['class'=>'btn btn-danger']) !!}
		</div>
	{!! Form::close() !!}

@endsection

HTMLのformとは異なるので、使いこなすには練習・復習が必要です。

Laravel Froms 1

Route::resource(‘/posts’, ‘PostsController’);

/posts/create.blade.php

@extends('layouts.app')


@section('content')

	<form method="post" action="/posts">
                {{ csrf_field()}}
		<input type="text" name="title" placeholder="Enter tilte">
		<input type="submit" name="submit">
	</form>

@endsection

@section('footer')
@endsection

PostsController

 public function create()
    {
        return view('posts.create');
    }

route
※index, store, create, show, update, destory, editにアクセスできるようになる

Route::resource('/posts', 'PostsController');

PostsController

public function create()
    {
        return view('posts.create');
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
        // return $request->all();

        Post::create($request->all());
    }

same behavior
return $request->get(‘title’);
return $request->title;

return $request->all();
{“_token”:”ANAHFf7WGgKgaEDvvpA7482QF8cAAZH1ifaBFjHa”,”title”:”sakura”,”submit”:”\u9001\u4fe1″}

よく見る書き方

$post = new Post;
        $post->title = $request->title;
        $post->save();

controller

public function index()
    {
        $posts = Post::all();
        return view("posts.index", compact('posts'));
    }

view

@section('content')
	<ul>
		@foreach($posts as $post)
		<li>{{$post->title}}</li>
		
		@endforeach
	</ul>
@endsection

controller: show

public function show($id)
    {
        $post = Post::findOrFail($id);
        return view('posts.show', compact('post'));
    }

view index.blade.php

<li><a href="{{ route('posts.show', $post->id) }}">{{$post->title}}</a></li>

controller: edit

public function edit($id)
    {
        //
        $post = Post::findOrFail($id);
        return view('posts.edit', compact('post'));

    }

view: edit

<h1>Edit Posts</h1>
	<form method="post" action="/posts/{{$post->id}}">
		{{ csrf_field()}}
		<input type="hidden" name="_method" value="PUT">
		<input type="text" name="title" placeholder="Enter tilte" value="{{$post->title}}">
		<input type="submit" name="submit">
	</form>

controller: update

public function update(Request $request, $id)
    {
        //
        $post = Post::findOrFail($id);

        $post->update($request->all());

        return redirect('posts');
    }

view: show

<h1><a href="{{route('posts.edit', $post->id)}}">{{$post->title}}</a></h1>

controller: delete

public function destroy($id)
    {
        $post = Post::findOrFail($id);
        $post->delete();
        return redirect('/posts');
    }

viiew:delete

<h1>Edit Posts</h1>
	<form method="post" action="/posts/{{$post->id}}">
		{{ csrf_field()}}
		<input type="hidden" name="_method" value="PUT">
		<input type="text" name="title" placeholder="Enter tilte" value="{{$post->title}}">
		<input type="submit" name="submit" value="UPDATE">
	</form>

	<form method="post" action="/posts/{{$post->id}}">
		{{ csrf_field()}}
		<input type="hidden" name="_method" value="DELETE">
		<input type="submit" value="DELETE">
	</form>

OK, まだ基礎の基礎
毎度のことだが、ボリュームの見積もりが甘すぎた

Polymorphic many to many relation(morphToMany)

The last of laravel database relation.

$ php artisan make:model Post -m
$ php artisan make:model Video -m
$ php artisan make:model Tags -m

Schema::create('videos', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });

$ php artisan make:model Taggable -m

Schema::create('taggables', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('tag_id');
            $table->integer('taggable_id');
            $table->string('taggable_type');
            $table->timestamps();
        });

$ php artisan migrate

Post.php, Video.php

    protected $fillable = ['name'];
    public function tags(){
    	return $this->norphToMany('App\Tags', 'taggable');
    }

Tags.php

class Tags extends Model
{
    protected $fillable = ['name'];
}

insert into tags (name) values (‘php’);
insert into tags (name) values (‘ruby’);
model name間違えた。。
alter table taggables change column tag_id tags_id int;

Route::get('/create', function(){

	$post = Post::create(['name'=>'my frist post']);
	$tag1 = Tags::findOrFail(1);
	$post->tags()->save($tag1);

	$video = Video::create(['name'=>'video.now']);
	$tag2 = Tags::findOrFail(2);
	$video->tags()->save($tag2);

});

read

Route::get('/read', function(){

	$post = Post::findOrFail(9);
	foreach($post->tags as $tag){
		echo $tag;
	}
});

update

Route::get('/update', function(){

	$post = Post::findOrFail(9);
	foreach($post->tags as $tag){
		$tag->whereId(1)->update(['name'=>'google']);
	}
});

delete

Route::get('/delete', function(){

	$post = Post::find(1);

	foreach($post->tags as $tag){
		$tag->whereId(1)->delete();
	}
});