laravelのsoftdeleteとは?

softdeleteとは?
聞きなれない言葉ですが、論理削除の意味です。
論理削除とは、表面上は削除されるが、データはテーブルに残っている状態

migrationで、softdeletesメソッドを呼び出し、use softdetesとします。

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    //
    use SoftDeletes;

    protected $dates = ['deleted_at'];
    // protected $table = 'posts'; 
	protected $fillable = [
		'title',
		'content'
	];
}

さらにmigrationファイルを追加

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

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            //'
                        $table->dropColumn('deleted_at');
        });
    }

route

Route::get('/softdelete', function(){
		Post::find(1)->delete();
});

mysql> select * from posts;
+—-+——————-+—————————————————+———————+———————+———-+———————+
| id | title | content | created_at | updated_at | is_admin | deleted_at |
+—-+——————-+—————————————————+———————+———————+———-+———————+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | 2019-12-06 05:35:12 | 0 | 2019-12-06 05:35:12 |
| 4 | new ORM title 2 | wow eloquent is really cool, look at this content | 2019-12-05 18:23:33 | 2019-12-05 18:33:31 | 0 | NULL |
| 6 | php create method | Wow I’m learning a lot | 2019-12-06 05:09:21 | 2019-12-06 05:09:21 | 0 | NULL |
+—-+——————-+—————————————————+———————+———————+———-+———————+
3 rows in set (0.00 sec)

アプリケーションでユーザがアカウント削除するが、論理データはテーブルに残す時などに使えそうです。

Route::get('/readofsoftdelete', function(){
		$post = Post::find(1);
		return $post;
});

soft deleteのレコードは、eloquentでfindしようとしても、blank扱いとなります^^
beautiful than expected

Route::get('/readofsoftdelete', function(){
		// $post = Post::find(1);
		// return $post;
		$post = Post::withTrashed()->where('id', 1)->get();
		return $post;
});

[{“id”:1,”title”:”Update tile”,”content”:”Laravel is the best thing that happen to PHP”,”created_at”:null,”updated_at”:”2019-12-06 05:35:12″,”is_admin”:0,”deleted_at”:”2019-12-06 05:35:12″}]

onlyTrashedでsoftdeleted itemを呼び出すこともできる

Route::get('/readofsoftdelete', function(){
		// $post = Post::find(1);
		// return $post;
		// $post = Post::withTrashed()->where('id', 1)->get();
		// return $post;
		$post = Post::onlyTrashed()->where('is_admin', 0)->get();
		return $post;

});

eloquent update

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

	Post::where('id', 3)->update(['title'=>'new php title','content'=>'I found it']);
});

mysql> select * from posts;
+—-+——————-+——————————————————+———————+———————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+——————-+——————————————————+———————+———————+———-+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
| 3 | laravel awesome | Laravel is the best thing that happen to PHP, period | NULL | NULL | 0 |
| 4 | new ORM title 2 | wow eloquent is really cool, look at this content | 2019-12-05 18:23:33 | 2019-12-05 18:33:31 | 0 |
| 5 | php create method | Wow I’m learning a lot | 2019-12-05 18:47:53 | 2019-12-05 18:47:53 | 0 |
+—-+——————-+——————————————————+———————+———————+———-+
4 rows in set (0.00 sec)

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

	$post = Post::find(5);

	$post->delete();
});
Route::get('/delete2', function(){
	Post::destroy(3);
});

あ、何故deleteではなくdestroyの名称が使われているかわかりました。

MassAssignmentException

create methodで書くと、MassAssignmentExceptionとなる

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

	Post::create(['title'=>'php create method', 'content'=>'Wow I\'m learning a lot']);
	
});

その場合は、modelでfillableに配列としてカラム名を記入する

class Post extends Model
{
    //
    // protected $table = 'posts'; 
	protected $fillable = [
		'title',
		'content'
	]
}

mysql> select * from posts;
+—-+——————-+——————————————————+———————+———————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+——————-+——————————————————+———————+———————+———-+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
| 3 | laravel awesome | Laravel is the best thing that happen to PHP, period | NULL | NULL | 0 |
| 4 | new ORM title 2 | wow eloquent is really cool, look at this content | 2019-12-05 18:23:33 | 2019-12-05 18:33:31 | 0 |
| 5 | php create method | Wow I’m learning a lot | 2019-12-05 18:47:53 | 2019-12-05 18:47:53 | 0 |
+—-+——————-+——————————————————+———————+———————+———-+

curious

Eloquent insert

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

	$post = new Post();

	$post->title = 'new ORM title';
	$post->content = 'wow eloquent is really cool, look at this content';
	$post->save();
});

mysql> select * from posts;
+—-+—————–+——————————————————+———————+———————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+—————–+——————————————————+———————+———————+———-+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
| 3 | laravel awesome | Laravel is the best thing that happen to PHP, period | NULL | NULL | 0 |
| 4 | new ORM title | wow eloquent is really cool, look at this content | 2019-12-05 18:23:33 | 2019-12-05 18:23:33 | 0 |
+—-+—————–+——————————————————+———————+———————+———-+
3 rows in set (0.00 sec)

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

	$post = Post::find(4);

	$post->title = 'new ORM title 2';
	$post->content = 'wow eloquent is really cool, look at this content';
	$post->save();
});

mysql> select * from posts;
+—-+—————–+——————————————————+———————+———————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+—————–+——————————————————+———————+———————+———-+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
| 3 | laravel awesome | Laravel is the best thing that happen to PHP, period | NULL | NULL | 0 |
| 4 | new ORM title 2 | wow eloquent is really cool, look at this content | 2019-12-05 18:23:33 | 2019-12-05 18:33:31 | 0 |
+—-+—————–+——————————————————+———————+———————+———-+
3 rows in set (0.00 sec)

update methodとは異なる概念のようです。

Eloquent get()

use App\Post;
Route::get('/findwhere', function(){
	$posts = Post::where('id', 1)->orderBy('id', 'desc')->take(1)->get();
	return  $posts;

});

[{“id”:1,”title”:”Update tile”,”content”:”Laravel is the best thing that happen to PHP”,”created_at”:null,”updated_at”:null,”is_admin”:0}]

確かにraw queryのselect * fromよりもeasy to understand
DB::select(‘select * from posts where id = ?’, [1]);

FindOrFail()とも書ける

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

	$posts = Post::findOrFail(4);
	return $posts;

});

eloquentって何?

Laravelのドキュメントを読んでいると、eloquentってワードが何度も出てきます。
なんとなく雰囲気でわかったような気でいましたが、eloquentって何でしょうか?
tinker・controllerでやっている以下のようなことでしょうか?

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

Model:model is a class that deal with database

モデルの作成
$ php artisan make:model Post
Model created successfully.

appフォルダにPost.phpが作られる
eloquentとは下のコードからもわかる様に、Modelのclass

databaseのtable nameがpostsなら、model nameはPost

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    //
    posts 
}
use App\Post;
Route::get('/read', function(){

	$posts = Post::all();

	foreach($posts as $post){
		return $post->title;
	}
});

update & delete

update with raw query

Route::get('update', function(){
	$update = DB::update('update posts set title ="Update tile" where id = ?',[1]);

	return $update;
});

mysql> select * from posts;
+—-+——————+———————————————-+————+————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+——————+———————————————-+————+————+———-+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
| 2 | php with laravel | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
+—-+——————+———————————————-+————+————+———-+
2 rows in set (0.00 sec)

Route::get('delete', function(){
	$delete = DB::delete('delete from posts where id = ?', [2]);
	return $delete;
});

mysql> select * from posts;
+—-+————-+———————————————-+————+————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+————-+———————————————-+————+————+———-+
| 1 | Update tile | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
+—-+————-+———————————————-+————+————+———-+
1 row in set (0.00 sec)

absolutely I godit.

Raw SQL Queryでselect * from

DB classでselectして$resultに格納する
あれ、exceptionになる。。

Route::get('/read', function(){
	$result = DB::select('select * from posts where id = ?', [1]);
	return $result->title;

});

あれ、これなら上手くいく

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

	$results = DB::select('select * from posts where id = ?', [1]);

	foreach($results as $post){
		return $post->title;
	}

});

debugしながらやらないと駄目のようです。

Route::get('/read', function(){
	$results = DB::select('select * from posts where id = ?', [1]);
	return $results;
});

[{“id”:1,”title”:”php with laravel”,”content”:”Laravel is the best thing that happen to PHP”,”created_at”:null,”updated_at”:null,”is_admin”:0}]

ここまでくれば、update, deleteの想像がつきます。

save();ではなく、DB::insertでinsert

Raw SQL Query

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

	DB::insert('insert into posts(title, content) values(?, ?)', ['php with laravel', 'Laravel is the best thing that happen to PHP']);
});

mysql> select * from posts;
+—-+——————+———————————————-+————+————+———-+
| id | title | content | created_at | updated_at | is_admin |
+—-+——————+———————————————-+————+————+———-+
| 1 | php with laravel | Laravel is the best thing that happen to PHP | NULL | NULL | 0 |
+—-+——————+———————————————-+————+————+———-+
1 row in set (0.00 sec)

以下のようにclassに対して値を入れてsave();とする方法とは異なる

public function store(Request $request){
    	$post = new Post();
    	$post->title = $request->title;
    	$post->body = $request->body;
    	$post->save();
    	return redirect('/');
    }

sqlに慣れていると、Raw SQL Queryの方が馴染みがあります。

migration後にカラムを追加したい時

カラム追加の場合は、table nameを指定してmake:migration
php artisan make:migration add_is_admin_column_to_posts_table –table=”posts”

dropも忘れずに書く
unsignedはnot negative number

public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $table->integer('is_admin')->unsigned();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $table->dropColumn('is_admin');
        });
    }

mysql> describe posts;
+————+——————+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+————+——————+——+—–+———+—————-+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| content | text | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| is_admin | int(10) unsigned | NO | | NULL | |
+————+——————+——+—–+———+—————-+
6 rows in set (0.01 sec)

public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            //
            $table->tinyInteger('is_admin')->default('0');
        });
    }

migrate:resetはall rollback
$ php artisan migrate:reset
Rolled back: 2019_12_05_083227_add_is_admin_column_to_posts_table
Rolled back: 2019_12_05_072639_create_posts_table
Rolled back: 2014_10_12_100000_create_password_resets_table
Rolled back: 2014_10_12_000000_create_users_table

migrate:refreshはresetとmigrateを同時に行う
$ php artisan migrate:refresh

ステータス表示
$ php artisan migrate:status
+——+——————————————————+
| Ran? | Migration |
+——+——————————————————+
| Y | 2014_10_12_000000_create_users_table |
| Y | 2014_10_12_100000_create_password_resets_table |
| Y | 2019_12_05_072639_create_posts_table |
| Y | 2019_12_05_083227_add_is_admin_column_to_posts_table |
+——+——————————————————+

カラムの編集・追加の度にmigration fileを追加するのか、resetで対応するかはどうなんだろう?
resetの方が、tableごとに管理できるので管理しやすそうだが、migration fileを追加していくのは、時系列で追えるメリットがある。