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();
	}
});

Polymorphic relation

Polymorphicの例は、staffの写真と商品の写真をphotosというテーブルで管理し、staffと商品を連携させることです。

$ php artisan make:model Staff -m

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

$ php artisan make:model Product -m

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

$ php artisan make:model Photo -m

Schema::create('photos', function (Blueprint $table) {
            $table->increments('id');
            $table->string('path');
            $table->integer('imageable_id');
            $table->string('imageable_type');
            $table->timestamps();
        });

$ php artisan migrate

Photo.php

public function imageable(){
    	return $this->morphTo();
    }

Staff.php, Product.php

public function photos(){
    	return $this->morphMany('App\Photo', 'imageable');
    }

staffsとproductsのテーブルにレコード挿入
mysql> insert into staff (name) values (‘peter’);
Query OK, 1 row affected (0.06 sec)

mysql> insert into staff (name) values (‘john’);
Query OK, 1 row affected (0.00 sec)

mysql> insert into product (name) values (‘laravel’);
ERROR 1146 (42S02): Table ‘polymorphic.product’ doesn’t exist
mysql> insert into products (name) values (‘laravel’);
Query OK, 1 row affected (0.01 sec)

mysql> insert into products (name) values (‘cake’);
Query OK, 1 row affected (0.00 sec)

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

	$staff = Staff::find(1);
	$staff->photos()->create(['path'=>'example.jpg']);

});

read

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

	$staff = Staff::findOrFail(1);

	foreach($staff->photos as $photo){
		return $photo->path;
	}

});

update

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

	$staff = Staff::findOrFail(1);

	$photo = $staff->photos(1)->whereId(2)->first();

	$photo->path = "update exampl.jpg";
	$photo->save();
});

delete

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

	$staff = Staff::findOrFail(1);
	$staff->photos()->delete();
});

connect

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

	$staff = Staff::findOrFail(1);

	$photo = Pohoto::findOrFail(3);

	$staff->photos()->save($photo);

});

ManyToMany relation: belongsToMany

manytomanyはpivotテーブルを使って、子供のレコードを管理する

$ php artisan make:model Role -m
$ php artisan make:migration create_role_user_table –create=role_user

role_user

Schema::create('role_user', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->nullable()->index();
            $table->integer('role_id')->unsigned()->nullable()->index();
            $table->timestamps();
        });

role

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

$ php artisan migrate

User.php

public function roles(){

        return $this->belongsToMany('App\Role');
    }

Role.php

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

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

Route::get('/create', function(){
	$user = User::find(1);

	$role = new Role(['name'=>'adminstrator']);

	$user->roles()->save($role);

});

mysql> select * from role_user;
+—-+———+———+————+————+
| id | user_id | role_id | created_at | updated_at |
+—-+———+———+————+————+
| 1 | 1 | 1 | NULL | NULL |
+—-+———+———+————+————+
1 row in set (0.00 sec)

read

Route::get('/read', function(){
	$user = User::findOrFail(1);

	foreach($user->roles as $role){
		dd($role);
	}
});

update
has()で確認する


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

	$user = User::findOrFail(1);

	if($user->has('roles')){

		foreach($user->roles as $role){
			if($role->name == 'adminstrator'){
				$role->name = 'Adminstrator';
				$role->save();
			}
		}
	}
});

delete

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

	$user = User::findOrFail(1);

	$user->roles()->delete();

});

attach & delete

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

	$user = User::findOrFail(1);

	$user->roles()->attach(2);

});

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

	$user = User::findOrFail(1);

	$user->roles()->detach(2);

});

createだけでなく、attachとdeleteがあるってのは、理にかなってます。

OneToMany relation : hasMany()

$ php artisan make:model Post -m

   Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->nullable()->index();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });

$ php artisan migrate

User.php

public function posts(){
        return $this->hasMany('App\Post');
    }

Post.php

protected $fillable = [
    	'title',
    	'body'
    ];

$ php artisan tinker
Psy Shell v0.7.2 (PHP 7.1.7 — cli) by Justin Hileman
>>> App\User::create([‘name’=>’Peter’, ’email’=>’peter@gmail.com’, ‘password’=>’1234’]);
=> App\User {#634
name: “Peter”,
email: “peter@gmail.com”,
updated_at: “2019-12-08 18:25:17”,
created_at: “2019-12-08 18:25:17”,
id: 1,
}

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

	$user = User::findOrFail(1);

	$post = new Post(['title'=>'My first post', 'body'=>'I love laravel']);
	$user->posts()->save($post);
});

read

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

	$user = User::findOrFail(1);

	return $user->posts;
});
Route::get('/read', function(){

	$user = User::findOrFail(1);

	foreach($user->posts as $post){
		echo $post->title . "<br>";
	}
});

update

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

	$user = User::find(1);
	$user->posts()->whereId(1)->update(['title'=>'I love', 'body'=>'this is awsome, thank you']);
});
Route::get('/delete', function(){

	$user = User::find(1);
	$user->posts()->whereId(1)->delete();
});

insertはsave(), updateはupdate(), deleteはdelete()メソッドです。
大分つかめてきました。
keep going

OneToOne relation

$ php artisan make:model Address -m

migration file

{
        Schema::create('addresses', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned()->nullable();
            $table->string('name');
            $table->timestamps();
        });
    }

$ php artisan migrate

User.php

public function address(){
        return $this->hasOne('App\Address');
    }

//data挿入
mysql> use onetoone;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+——————–+
| Tables_in_onetoone |
+——————–+
| addresses |
| migrations |
| password_resets |
| users |
+——————–+
4 rows in set (0.00 sec)

mysql> insert into users (name, email, password) values (‘peter’, ‘peter@gmail’, ‘1234’);
Query OK, 1 row affected (0.00 sec)

Address.php

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

route.php

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

	$user = User::findOrFail(1);
	$address = New Address(['name'=>'1234 Huston av NY NY 11218']);
	$user->address()->save($address);
});

mysql> select * from addresses;
+—-+———+—————————-+———————+———————+
| id | user_id | name | created_at | updated_at |
+—-+———+—————————-+———————+———————+
| 1 | 1 | 1234 Huston av NY NY 11218 | 2019-12-08 04:19:29 | 2019-12-08 04:19:29 |
+—-+———+—————————-+———————+———————+
1 row in set (0.00 sec)

$user->save();のところを、hasOneでは$user->address()->save($address);って書くんだ。I aint know what’s going on inside.

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

	$address = Address::where('user_id', 1)->first();

	$address->name = "4532 Updated new address";
	$address->save();
});

mysql> select * from addresses;
+—-+———+—————————+———————+———————+
| id | user_id | name | created_at | updated_at |
+—-+———+—————————+———————+———————+
| 1 | 1 | 4532 Updated new address | 2019-12-08 04:19:29 | 2019-12-08 04:39:56 |
| 2 | 1 | 1234 Tokyo av NY NY 11218 | 2019-12-08 04:28:09 | 2019-12-08 04:28:09 |
+—-+———+—————————+———————+———————+
2 rows in set (0.00 sec)

updateは、対象のレコードを選択してsave();

read

Route::get('/read', function(){
	$user = User::findOrFail(1);
	return $user->address->name;	
});

delete

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

	$user = User::findOrFail(1);

	$user->address()->delete();
	
});

php tinker

$ php artisan tinker
>>> $post = App\Post::create([‘title’=>’php post from tinker’, ‘content’=>’content from tinker’]);

mysql> select * from posts;
+—-+———————-+———————+———————+———————+———-+————+
| id | title | content | created_at | updated_at | is_admin | deleted_at |
+—-+———————-+———————+———————+———————+———-+————+
| 1 | php post from tinker | content from tinker | 2019-12-08 03:09:23 | 2019-12-08 03:09:23 | 0 | NULL |
+—-+———————-+———————+———————+———————+———-+————+
1 row in set (0.00 sec)

異なる書き方
>>> $post = new App\Post;
=> App\Post {#627}
>>> $post->title = ‘new title’;
=> “new title”
>>> $post->content = ‘yea maybe conding’;
=> “yea maybe conding”
>>> $post->save();
=> true

mysql> select * from posts;
+—-+———————-+———————+———————+———————+———-+————+
| id | title | content | created_at | updated_at | is_admin | deleted_at |
+—-+———————-+———————+———————+———————+———-+————+
| 1 | php post from tinker | content from tinker | 2019-12-08 03:09:23 | 2019-12-08 03:09:23 | 0 | NULL |
| 2 | new title | yea maybe conding | 2019-12-08 03:13:19 | 2019-12-08 03:13:19 | 0 | NULL |
+—-+———————-+———————+———————+———————+———-+————+
2 rows in set (0.00 sec)

>>> $post = App\Post::find(2);
=> App\Post {#663
id: 2,
title: “new title”,
content: “yea maybe conding”,
created_at: “2019-12-08 03:13:19”,
updated_at: “2019-12-08 03:13:19”,
is_admin: 0,
deleted_at: null,
}

>>> $post = App\Post::find(2);
=> App\Post {#659
id: 2,
title: “new title”,
content: “yea maybe conding”,
created_at: “2019-12-08 03:13:19”,
updated_at: “2019-12-08 03:13:19”,
is_admin: 0,
deleted_at: null,
}
>>> $post->title = “update record with this”
=> “update record with this”
>>> $post->content = “also update record with 2”
=> “also update record with 2”
>>> $post->save();

>>> $post->delete();
=> true
>>> $post = App\Post::onlyTrashed()
=> Illuminate\Database\Eloquent\Builder {#666}
>>> $post->forceDelete();
=> 1
>>>

tinkerは挙動の簡単なテストなどに使える

many to many polymorphic relation

they share single id of unique record.

$ php artisan make:model Video -m

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

$ php artisan make:model Tag -m

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

$ php artisan make:model Taggable -m

public function up()
    {
        Schema::create('videos', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }
class Tag extends Model
{
    //

    public function posts(){

    	return $this->norphByMany('App\Post', 'taggables');
    }

    public function videos(){

    	return $this->norphByMany('App\Video', 'taggables');
    }
}

$php artisan migrate

mysql> insert into videos (name) values (‘the mule’);
Query OK, 1 row affected (0.01 sec)

mysql> insert into videos (name) values (‘coding’);
Query OK, 1 row affected (0.00 sec)

mysql> insert into tags (name) values (‘javascript’);
Query OK, 1 row affected (0.04 sec)

mysql> insert into tags (name) values (‘php’);
Query OK, 1 row affected (0.01 sec)

mysql> insert into taggables (tag_id, taggable_id, taggable_type) values (1, 1,’App\Video’);
Query OK, 1 row affected (0.00 sec)

mysql> insert into taggables (tag_id, taggable_id, taggable_type) values (2, 1,’App\Post’);
Query OK, 1 row affected (0.01 sec)

Route::get('/post/tags', function(){

	$post = Post::find(1);
	foreach($post->tags as $tag){
			echo $tag->name;
	}
});

Route::get('/tag/post', function(){

	$tag = Tag::find(1);
	foreach($tag->posts as $post){
		$echo $post->title;
	}

});

polymorphic は、テーブル関係が複雑なので復習が必要だ