Laravel手記

Laravel控制器


php artisan make:controller TaskController 
# 通過Artisan命令快速創(chuàng)建一個控制器
# 該命令會在 app/Http/Controllers 目錄下創(chuàng)建一個新的名為 TaskController.php 的文件
php artisan make:controller PostController --resource
# 使用 Artisan 生成器來生成一個資源控制器(在之前命名后加上 --resource 選項)
# 打開 app/Http/Controllers/PostController.php 文件,可看到 PostController 代碼

Route::resource('post', 'PostController');
# 寫在web.php文件中,一次注冊包含上面列出的所有路由

php artisan route:list
# Artisan命令,查看應(yīng)用的所有路由

資源控制器方法列表

資源控制器方法列表.png

路由進(jìn)階使用


Route::fallback(function(){
    return '我是最后的屏障';
});
# 兜底路由,請求無法匹配到的URL時返回的內(nèi)容

Route::middleware('throttle:60,1')->group(function(){
    Route::get('/user', function(){
        //
    });
})
# 一分鐘能只能訪問路由分組的內(nèi)路由(如 /user)60 次,超過此限制會返回 429 狀態(tài)碼并提示請求過于頻繁
# 通過內(nèi)置的throttle中間件來實現(xiàn),接受兩個參數(shù),第一個是次數(shù)上限,另一個是指定時間段(單位:分鐘

Route::middleware('throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        // 在 User 模型中設(shè)置自定義的 rate_limit 屬性值
    });
    Route::get('/post', function () {
        // 在 Post 模型中設(shè)置自定義的 rate_limit 屬性值
    });
});

php artisan route:cache
# 將所有路由定義轉(zhuǎn)化為控制器路由或資源路由后才能執(zhí)行路由緩存命令

php artisan route:clear
# 刪除路由緩存

表單方法偽造與跨站請求偽造攻擊防護


HTML 表單僅支持 GET 和 POST 兩種方式,
如果要使用其他的方式,則需要自己來定義實現(xiàn)

/**
 * Laravel 路由支持的 HTTP 請求方式
 *
 * @var array
 */
public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
# 相應(yīng)的路由定義方法

<form action="/task/1" method="POST"> 
    <input type="hidden" name="_method" value="DELETE"> 
</form>
# 表單請求方法偽造
# 在表單中加一個名為'_method'的隱藏字段,字段值是 PUT、DELETE、 PATCH

視圖入門


return view('以.分隔的視圖模板路徑');
# 視圖的定義方式

# 使用 view 輔助函數(shù)在路由中返回視圖
Route::get('/', function () { 
    // 該函數(shù)會在 resources/views 目錄下查找 home.blade.php 或 home.php 視圖文件,
    // 加載文件內(nèi)容并解析 PHP 變量或語句,然后傳遞給響應(yīng),最終呈現(xiàn)給用戶
    return view('home'); 
});

return view('home')->with('tasks', Task::all());
return view('home', ['tasks' => Task::all()]);
# 傳遞數(shù)據(jù)給視圖的方法,將tasks數(shù)據(jù)變量傳遞到視圖以便在視圖中引用

view()->share('siteName', 'Laravel學(xué)院');
view()->share('siteUrl', 'https://xueyuanjun.com');
# 通過視圖對象提供的share方法實現(xiàn)在視圖間共享變量
# 比如在AppServiceProvider 的 boot 方法中定義共享的視圖變量
# 然后就可以在各個視圖中使用 $siteName 和 $siteUrl 這兩個變量了(其它變量定義方式類似)

Blade入門篇


# Blade模板代碼實例
<h1>{{ $group->title }}</h1> 
{!! $group->imageHtml() !!} 
@forelse ($users as $user) 
    {{ $user->username }} {{ $user->nickname }}<br> 
@empty 
    該組中沒有任何用戶 
@endforelse

# 通過 {{ }} 渲染 PHP 變量(最常用)
# 通過 {!! !!} 渲染原生 HTML 代碼(用于富文本數(shù)據(jù)渲染)
# 通過以 @ 作為前綴的 Blade 指令執(zhí)行一些控制結(jié)構(gòu)和繼承、引入之類的操作

# Blade 模板代碼存放在以 .blade.php 后綴結(jié)尾的視圖文件中
# 編譯后的代碼位于 storage/framework/views 目錄下

{{ $variable }}
# 編譯后的最終代碼(避免XSS攻擊):
<?php echo htmlentities($variable); ?>

# 對于當(dāng)前端框架也用{{}}輸出js變量的情況
# 需要在渲染前端js變量的{{}}前面加上@前綴

# Blade 引擎會將其編譯為對應(yīng)的 PHP 代碼
{{ $phpData }}
# Blade 引擎編譯時會移除 @,保留 {{ $vueData }} 結(jié)構(gòu)
@{{ $vueData }}

# 條件語句
@if (count($students) === 1) 
    操場上只有一個同學(xué)
@elseif (count($students) === 0)
    操場上一個同學(xué)也沒有
@else
    操場上有 {{ count($students) }} 個同學(xué)
@endif

# 表示和 @if 條件相反的條件
@unless ($user->hasPaid()) 
    用戶沒有支付
@endunless

# 和 isset()  empty() 方法等價
@isset($records)
    // 記錄被設(shè)置
@endisset
@empty($records)
    // 記錄為空
@endempty

@switch($i)
    @case(1)
        // $i = 1 做什么
        @break
    @case(2)
        // $i = 2 做什么
        @break
    @default
        // 默認(rèn)情況下做什么
@endswitch

// for 循環(huán)
@for ($i = 0; $i < $talk->slotsCount(); $i++) 
    The number is {{ $i }}<br> 
@endfor

// foreach 循環(huán)
@foreach ($talks as $talk)
    {{ $talk->title }} ({{ $talk->length }} 分鐘)<br> 
@endforeach

// while 循環(huán)  
@while ($item = array_pop($items)) 
    {{ $item->orSomething() }}<br> 
@endwhile

@forelse ($students as $student)
    // do something ...
@empty
    // do something else ...
@endforelse
# 用于處理一下的PHP代碼邏輯:
<?php 
if ($students) {
    foreach ($students as $student) {
       // do something ...
    }
} else {
    // do something else ...
}
?>
$loop實例的屬性.png

Blade進(jìn)階篇

1.通過 @yield@section/@show 在布局文件中定義插槽。
2.通過 @extends@section/@endsection 在子視圖實現(xiàn)繼承。
3.通過 @include 引入其他視圖組件
4.通過 @each 指令循環(huán)引入單個組件,支持多個參數(shù)。
5.通過 @slot@component 實現(xiàn)更加靈活的內(nèi)容分發(fā)。

Blade高級篇


不知道寫啥...

使用Bootstrap、Vue


composer require laravel/ui #通過Composer下載安裝

# 初始化前端腳手架
php artisan ui bootstrap 
php artisan ui vue

npm install # 安裝應(yīng)用的前端依賴

npm run dev 

# 編寫Vue組件
# 將Vue組件寫在 resources/js/components目錄下

# 在resources/js/app.js中全局注冊
Vue.component('welcome-component', require('./components/WelcomeComponent.vue').default);

const app = new Vue({
    el: '#app'
});

# 完了修改welcome.blade.php代碼,再 npm run dev就好啦~
# Vue組件名開頭一定要大寫

使用Laravel Mix編譯前端資源


npm install # 安裝需要的依賴
npm run dev # 運行所有 Mix 任務(wù)
npm run watch # 監(jiān)控,發(fā)現(xiàn)修改后自動重新編譯文件

mix.less('resources/assets/less/app.less', 'public/css'); # 編譯 less 文件
mix.less('resources/assets/less/app.less', 'public/stylesheets/styles.css'); # 自定義編譯后文件的輸出位置
mix.sass('resources/assets/sass/app.scss', 'public/css'); # 編譯 sass 文件,同上
mix.stylus('resources/assets/stylus/app.styl', 'public/css'); # 編譯 stylus 文件

mix.js('resources/assets/js/app.js', 'public/js'); # 處理js

mix.js('resources/assets/js/app.js', 'public/js')
   .extract(['vue']) # 提取 Vendor 庫

mix.react('resources/assets/js/app.jsx', 'public/js'); # 支持 React

mix.copy('node_modules/foo/bar.css', 'public/css/bar.css'); # 拷貝文件/目錄

mix.js('resources/assets/js/app.js', 'public/js')
   .version(); # 緩存刷新
<link rel="stylesheet" href="{{ mix('css/app.css') }}"> # 在視圖中使用 Laravel 全局的 Mix 函數(shù)加載前端資源

mix.browserSync('my-domain.test');
// Or...
// https://browsersync.io/docs/options
mix.browserSync({
    proxy: 'my-domain.test'
});
# 自動監(jiān)控文件修改

通過遷移文件定義數(shù)據(jù)表結(jié)構(gòu)


$table->string('name', 100)->comment('用戶名');  # 為字段額外添加注釋信息
Schema::dropIfExists('user');  # 刪除表(在down()方法中

php artisan make:migration alter_users_add_nickname --table=users
# 修改表應(yīng)在新增遷移文件中操作
$table->string('nickname', 100)->after('name')->nullable()->comment('用戶昵稱');  # 新增 nickname 字段
$table->dropColumn('nickname');  # 刪除一個已存在的字段

composer require doctrine/dbal  # 對已存在的數(shù)據(jù)表字段修改,先安裝擴展包
$table->string('nickname', 50)->change();  # 修改字段長度
$table->renameColumn('name', 'username');  # 重命名字段

$table->string('email')->unique();  # 添加唯一索引
$table->increments('id');  # 創(chuàng)建自動增長的主鍵索引
$table->index(['name', 'email']);  # 支持一次傳入多個字段,構(gòu)建混合索引

# ↓不推薦使用,影響數(shù)據(jù)庫性能
$table->foreign('user_id')->references('id')->on('users');
# 建立文章表中的 user_id 字段與用戶表中的 id 之間的關(guān)聯(lián)關(guān)系
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade');
# 外鍵約束
$table->dropForeign(['user_id']); # 刪除外鍵索引

php artisan migrate  # 執(zhí)行變更
php artisan migrate:rollback  # 回滾最后一個遷移文件的變更
php artisan migrate:rollback --step=5  # 回滾多個遷移文件的變更,可以通過 --step= 指定步數(shù)
 php artisan migrate:reset  # 回滾所有遷移文件的變更,將數(shù)據(jù)庫恢復(fù)到初始狀態(tài)

通過填充器快速填充測試數(shù)據(jù)


database/seeds/DatabaseSeeder.php

php artisan db:seed  # 一次性調(diào)用所有填充器
# 需要將所有對其他填充器的調(diào)用定義在該方法中↓
$this->call(UsersTableSeeder::class);

php artisan db:seed --class=UsersTableSeeder  # 指定某個填充器類的run方法 

php artisan make:seeder UsersTableSeeder  # 為users表快速創(chuàng)建一個填充器類 UsersTableSeeder
eg: # 填充邏輯
public function run()
{
    DB::table('users')->insert([
        'name' => \Str::random(10),
        'email' => \Str::random(10).'@gmail.com',
        'password' => bcrypt('secret'),
    ]);
}
# laravel 7 str_random()無效,應(yīng)改成如上\Str::random

php artisan db:seed --class=UsersTableSeeder # 運行
# 也可以在DatabaseSeeder 類的 run 方法中運行這個填充器類
# 適用于多個填充器類一次運行的情況↓
public function run()
{
    $this->call(UsersTableSeeder::class);
}
# 然后↓
php artisan db:seed

# Laravel 自帶一個用于填充 User 模型的模型工廠 UserFactory.php
php artisan make:factory PostFactory --model=Post # 為模型類創(chuàng)建一個模型工廠
# 在UsersTableSeeder 的 run 方法中通過模型工廠改寫數(shù)據(jù)填充方法↓
# 傳入對應(yīng)模型類和要填充的記錄數(shù)
factory(\App\User::class, 5)->create();
php artisan db:seed --class=UsersTableSeeder
  # 運行命令來填充數(shù)據(jù)庫

通過查詢構(gòu)建器實現(xiàn)簡單的增刪改查操作


在laravel中不要通過 DB 門面提供的 statement 方法執(zhí)行原生的 SQL Statement 語句,比如創(chuàng)建、刪除、修改數(shù)據(jù)表操作,這些操作可以通過數(shù)據(jù)庫遷移來實現(xiàn),而且可維護性更好。

# 寫在控制器里

$users = DB::select('select * from `users`');  # 查,返回所有結(jié)果的對象數(shù)組

# 指定查詢條件,借助 PDO 的參數(shù)綁定功能來防范 SQL 注入
$name = 'kong';
$users = DB::select('select * from `users` where `name` = ?', [$name]);

# 改
$name = '空空';
$id = 1;
$affectedRows = DB::update('update `users` set `name` = ? where id = ?', [$name, $id]);

# 刪
$id = 7;
$affectedRows = DB::delete('delete from `users` where id = ?', [$id]);

# 使用查詢構(gòu)建器進(jìn)行增刪改查
$users = DB::table('users')->get();  # 查
# 指定查詢條件,無需手動設(shè)置參數(shù)綁定來規(guī)避 SQL 注入攻擊
$name = '空空';
$users = DB::table('users')->where('name', $name)->get();  
$user = DB::table('users')->where('name', $name)->first(); # 返回查詢結(jié)果中的第一條記錄
$user = DB::table('users')->select('id', 'name', 'email')->where('name', $name)->first();  # 指定查詢的字段

# 增/插入記錄
$flag = DB::table('users')->insert([
    'name' => \Str_random(10),
    'email' => \Str_random(8) . '@163.com',
    'password' => bcrypt('secret')
]);

# 插入之后獲取對應(yīng)記錄的主鍵 ID
$userId = DB::table('users')->insertGetId([
    'name' => \Str_random(10),
    'email' => \Str_random(8) . '@qq.com',
    'password' => bcrypt('secret')
]);

# 支持一次插入多條記錄

# 改/更新
$id = 11;
$affectedRows = DB::table('users')->where('id', '>', $id)->update(['name' => \Str_random(8)]);
# where 方法第二個參數(shù)省略的話,默認(rèn)是 =
# 如果不是相等條件需要手動指定該參數(shù)值, > 大于,< 小于,和比較運算符一致

# 刪
$id = 11;
$affectedRows = DB::table('users')->where('id', '>=', $id)->delete();

$affectedRows = DB::table('users')->delete(); # 清空
$affectedRows = DB::table('users')->truncate(); # 清空后重置自增ID

通過查詢構(gòu)建器實現(xiàn)復(fù)雜的查詢語句


$name = '空空';
$email = DB::table('users')->where('name', $name)->value('email');  # 直接獲取指定字段的值
$exists = DB::table('users')->where('name', $name)->exists(); # 判斷字段值是否存在
$users = DB::table('users')->where('id', '<', 10)->pluck('name', 'id'); # 構(gòu)建關(guān)聯(lián)數(shù)組
# ↑鍵對應(yīng)的字段在后面,值對應(yīng)的字段在前面

# 避免一次返回所有值超出php內(nèi)存限制的辦法
# 對 users 按照 id 字段升序排序后將獲取的結(jié)果集每次返回5個進(jìn)行處理,將用戶名依次放到 $names 數(shù)組中
$names = [];
DB::table('users')->orderBy('id')->chunk(5, function ($users) use (&$names) {
    foreach ($users as $user) {
        $names[] = $user->name;
    }
});

# 聚合函數(shù)
$num = DB::table('users')->count();       # 計數(shù)     9
$sum = DB::table('users')->sum('id');     # 求和    45
$avg = DB::table('users')->avg('id');     # 平均值   5
$min = DB::table('users')->min('id');     # 最小值   1
$max = DB::table('users')->max('id');     # 最大值   9

# 基礎(chǔ)查詢
DB::table('posts')->where('views', 0)->get();      # 此處等號可以省略
DB::table('posts')->where('views', '>', 0)->get(); # 字段名,運算符,比較值
DB::table('posts')->where('title', 'like', 'Laravel學(xué)院%')->get(); # 模糊查詢

DB::table('posts')->where('id', '<', 10)->where('views', '>', 0)->get(); # 多個條件
DB::table('posts')->where([
    ['id', '<', 10],
    ['views', '>', 0]
])->get(); # 另一種寫法
DB::table('posts')->where('id', '<', 10)->orWhere('views', '>', 0)->get(); # or條件的查詢
DB::table('users')->whereBetween('id', [2, 4])->get(); # between查詢
DB::table('users')->whereNotBetween('id', [2, 4])->get(); # 獲取不在指定區(qū)間的記錄
DB::table('posts')->whereIn('id', [1, 3, 5, 7, 9])->get(); # in查詢,還有whereNotIn
DB::table('users')->whereNull('email')->get(); # NULL查詢,還有whereNotNull

# 日期查詢
DB::table('posts')->whereYear('created_at', '2018')->get();   # 年
DB::table('posts')->whereMonth('created_at', '11')->get();    # 月
DB::table('posts')->whereDay('created_at', '28')->get();      # 一個月的第幾天
DB::table('posts')->whereDate('created_at', '2018-11-28')->get();  # 具體日期
DB::table('posts')->whereTime('created_at', '14:00')->get();  # 時間

DB::table('posts')->whereColumn('updated_at', '>', 'created_at')->get(); # 字段相等查詢

DB::table('users')
    ->where('options->language', 'en')
    ->get(); # JSON屬性查詢
DB::table('users')
    ->whereJsonContains('options->languages', 'en_US')
    ->get();
DB::table('users')
    ->whereJsonContains('options->languages', ['en_US', 'zh_CN'])
    ->get(); # 數(shù)組的包含查詢

# 參數(shù)分組
select * from posts where id <= 10 or (views > 0 and created_at < '2018-11-28 14:00');
# 查詢構(gòu)建器的實現(xiàn)↓
DB::table('posts')->where('id', '<=', 10)->orWhere(function ($query) {
    $query->where('views', '>', 0)
        ->whereDate('created_at', '<', '2018-11-28')
        ->whereTime('created_at', '<', '14:00');
})->get();

# where exists
select * from `users` where exists (select 1 from `posts` where posts.user_id = users.id);
# 查詢構(gòu)建器的實現(xiàn)↓
DB::table('users')
    ->whereExists(function ($query) {
        $query->select(DB::raw(1))
            ->from('posts')
            ->whereRaw('posts.user_id = users.id');
    })
->get();

# 子查詢
select * from posts where user_id in (select id from users where email_verified_at is not null);
# 查詢構(gòu)建器的實現(xiàn)↓
$users = DB::table('users')->whereNotNull('email_verified_at')->select('id');
$posts = DB::table('posts')->whereInSub('user_id', $users)->get();

創(chuàng)建并填充posts表

php artisan make:migration create_posts_table --create=posts # 新建 posts 數(shù)據(jù)表

# 在CreatePostsTable 的 up里:
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title')->comment('標(biāo)題');
        $table->text('content')->comment('內(nèi)容');
        $table->integer('user_id')->unsigned()->default(0);
        $table->integer('views')->unsigned()->default(0)->comment('瀏覽數(shù)');
        $table->index('user_id');
        $table->timestamps();
    });
}

php artisan migrate # 創(chuàng)建表
php artisan make:model Post # 創(chuàng)建模型類
php artisan make:factory PostFactory --model=Post # 創(chuàng)建模型工廠

# database/factories/PostFactory.php:
$factory->define(\App\Post::class, function (Faker $faker) {
    return [
        'title' => $faker->title,
        'content' => $faker->text,
        'user_id' => mt_rand(1, 15),
        'views' => $faker->randomDigit
    ];
});

php artisan make:seeder PostsTableSeeder # 為posts表創(chuàng)建填充類

# PostsTableSeeder里:
public function run()
    {
        factory(\App\Post::class, 30)->create();
    }

php artisan db:seed --class=PostsTableSeeder  # 填充 posts 數(shù)據(jù)表
# 內(nèi)連接
$posts = DB::table('posts')
    ->join('users', 'users.id', '=', 'posts.user_id')
    ->select('posts.*', 'users.name', 'users.email')
    ->get();
# 當(dāng)兩張表有字段名相同的字段并被select指定時,要區(qū)別名
select('posts.*', 'users.name as username', 'users.email')

# 左連接
$posts = DB::table('posts')
    ->leftJoin('users', 'users.id', '=', 'posts.user_id')
    ->select('posts.*', 'users.name', 'users.email')
    ->get();

# 右連接 
$posts = DB::table('posts')
    ->rightJoin('users', 'users.id', '=', 'posts.user_id')
    ->select('posts.*', 'users.name', 'users.email')
    ->get();


DB::table('posts')->orderBy('created_at', 'desc')->get(); # # 按照創(chuàng)建時間進(jìn)行逆序排序
DB::table('posts')->orderBy('created_at')->get(); # 升序排序
DB::table('posts')->inRandomOrder()->get(); # 隨機排序(結(jié)果集很大的不要用,性能比較差

# 分組
$posts = DB::table('posts')
    ->groupBy('user_id')
    ->selectRaw('user_id, sum(views) as total_views')
    ->having('total_views', '>=', 10) # 對分組結(jié)果進(jìn)行過濾
    ->get();

# 分頁
$posts = DB::table('posts')->orderBy('created_at', 'desc')
    ->where('views', '>', 0)
    ->skip(10) # 表示從第幾條記錄開始,也可以用 offset()
    ->take(5) # 表示一次獲取多少條記錄,也可以用 limit()
    ->get();

通過 Eloquent 模型實現(xiàn)簡單增刪改查操作


Eloquent 約定模型類映射表名是將類名由駝峰格式轉(zhuǎn)化為小寫+下劃線(含多個單詞的話),最后將其轉(zhuǎn)化為復(fù)數(shù)形式,比如 Post 對應(yīng)表名是 posts、PostTag 對應(yīng)表名是 post_tags
Eloquent 默認(rèn)約定每張表都有 created_atupdated_at 字段(遷移類中 $table->timestamps() 會生成這兩個字段),并且在保存模型類時會自動維護這兩個字段。

# 創(chuàng)建模型類
php artisan make:model Post # 這樣生成Post.php在app目錄下
php artisan make:model Models/Post # 如果要指定創(chuàng)建的model到某個目錄,可以先`目錄名稱/model名字`,這里會將Post.php存放到app/Models目錄下

protected $primaryKey = 'post_id'; # 設(shè)置自增主鍵,默認(rèn)為id
public $incrementing = false; # 設(shè)置非自增主鍵
protected $keyType = 'string'; # 設(shè)置非整型主鍵

public $timestamps = false; # 不設(shè)置時間戳
public const CREATED_AT = 'create_time';
public const UPDATED_AT = 'update_time'; # 設(shè)置自定義的創(chuàng)建和更新時間字段
protected $dateFormat = 'U'; # 自定義時間戳的格式,這里設(shè)置為Unix 時間戳

protected $connection = 'connection_name'; # 為模型類指定使用哪個連接

$posts = Post::all(); # 獲取一張表的所有記錄

foreach ($posts as $post) {
    dump($post->title);
} # 獲取指定模型類的字段屬性,遍歷

foreach (Post::cursor() as $post) {
    dump($post->title . ':' . $post->content);
} # 每次只獲取一條查詢結(jié)果,最大限度減少內(nèi)存消耗

$posts = Post::where('views', '>', 0)
    ->select('id', 'title', 'content') # 指定查詢條件和查詢字段
    ->get(); 

$posts = Post::where('views', '>', 0)
    ->orderBy('id', 'desc')
    ->offset(10)
    ->limit(5)
    ->get(); # 排序分頁

$user = User::where('name', '空空')->first(); # 獲取單條記錄
$user = User::find(1); # 簡化↑

# 聚合結(jié)果
$num = User::whereNotNull('email_verified_at')->count();       # 計數(shù)     
$sum = User::whereNotNull('email_verified_at')->sum('id');     # 求和    
$avg = User::whereNotNull('email_verified_at')->avg('id');     # 平均值   
$min = User::whereNotNull('email_verified_at')->min('id');     # 最小值   
$max = User::whereNotNull('email_verified_at')->max('id');     # 最大值

# 插入數(shù)據(jù)
$post = new App\Post;
$post->title = '測試文章標(biāo)題';
$post->content = '測試文章內(nèi)容';
$post->user_id = 1;
$post->save();

# 更新
$post = Post::find(31);
$post->title = '測試文章標(biāo)題更新';
$post->save();

Post::where('views', '>', 0)->update(['views' => 100]); # 批量更新

# 刪除
$post = Post::find(31);
$post->delete();

# 一次刪除多條記錄,通過數(shù)組傳遞多個主鍵 ID
Post::destroy([1,2,3]); 

# 刪除指定記錄
$user = User::where('name', '空空')->fisrt();
$user->delete();

通過 Eloquent 模型實現(xiàn)批量賦值和軟刪除


$post = new Post([
    'title' => '測試文章標(biāo)題', 
    'content' => '測試文章內(nèi)容'
]); # 將待設(shè)置屬性以關(guān)聯(lián)數(shù)組的方式傳遞構(gòu)造函數(shù)
$post = new Post($request->all()); # 批量賦值,等同于上面的賦值方式

// 注意:白名單與黑名單不可同時使用
/**
 *(白名單) 使用批量賦值的屬性,只有在這里設(shè)置的字段才會批量賦值
 * @var array
 */
protected $fillable = [];

/**
 * (黑名單) 不使用批量賦值的字段,如果為星號表示所有字段都不賦值
 *
 * @var array
 */
protected $guarded = ['*'];

# 更新
$post = Post::findOrFail(1);  # 獲取相應(yīng)id的數(shù)據(jù),沒有相應(yīng)數(shù)據(jù)會報錯404
$post->fill($request->all());
$post->save();

# 通過數(shù)據(jù)庫遷移添加deleted_at字段,實現(xiàn)軟刪除
php artisan make:migration alter_posts_add_deleted_at --table=posts
# 在遷移文件中:
public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->softDeletes();
        });
    }
public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropColumn('deleted_at');
        });
    }
php artisan migrate # 執(zhí)行變更
# 在模型類中:
use SoftDeletes;

# 判斷是否被刪除
$post = Post::findOrFail(2); # 獲取指定id數(shù)據(jù)
$post->delete(); # 刪了它!
if ($post->trashed()) {
    dump('該記錄已刪除');
} # 通過 trashed() 查詢

$post = Post::onlyTrashed()->where('views', 0)->get(); # 獲取被軟刪除的數(shù)據(jù)
$post = Post::onlyTrashed()->where('views', 0)->get(); # 物理刪除,整條數(shù)據(jù)直接沒咯

在 Eloquent 模型類上設(shè)置訪問器和修改器


# 要實現(xiàn)這樣的邏輯:
if ($user->nickname) {
    $user->display_name = $user->nickname;  // 顯示用戶名為用戶昵稱
} else {
    $user->display_name = $user->name;  // 顯示用戶名為注冊時的用戶名
}
# 應(yīng)在user模型類中設(shè)置對應(yīng)方法(訪問器
public function getDisplayNameAttribute() 
{
    return $this->nickname ? $this->nickname : $this->name;
}
# 方法名不能設(shè)置為 getNameAttribute之類的,這樣會與數(shù)據(jù)庫字段重復(fù),報錯

# 在字段值保存到數(shù)據(jù)庫之前進(jìn)行一定處理滿足需求后再存(修改器
public function setCardNoAttribute($value)
{
    $value = str_replace(' ', '', $value);  // 將所有空格去掉
    $this->attributes['card_no'] = encrypt($value);
}
# 通過模型類保存一個銀行卡號到數(shù)據(jù)庫
$user = User::find(1);
$user->card_no = '6222020903001483077';
$user->save();

# 數(shù)據(jù)&JSON轉(zhuǎn)化
# 新建字段settings(MySQL 5.7以下的版本設(shè)置字段類型為TEXT格式
protected $casts = [
    'settings' => 'array'
];

laravel查看數(shù)據(jù)庫的版本dd(DB::select("select version()"));

Eloquent 模型事件和監(jiān)聽方式大全


所有支持的模型事件:

  • retrieved:獲取到模型實例后觸發(fā)
  • creating:插入到數(shù)據(jù)庫前觸發(fā)
  • created:插入到數(shù)據(jù)庫后觸發(fā)
  • updating:更新到數(shù)據(jù)庫前觸發(fā)
  • updated:更新到數(shù)據(jù)庫后觸發(fā)
  • saving:保存到數(shù)據(jù)庫前觸發(fā)(插入/更新之前,無論插入還是更新都會觸發(fā))
  • saved:保存到數(shù)據(jù)庫后觸發(fā)(插入/更新之后,無論插入還是更新都會觸發(fā))
  • deleting:從數(shù)據(jù)庫刪除記錄前觸發(fā)
  • deleted:從數(shù)據(jù)庫刪除記錄后觸發(fā)
  • restoring:恢復(fù)軟刪除記錄前觸發(fā)
  • restored:恢復(fù)軟刪除記錄后觸

Eloquent 模型關(guān)聯(lián)關(guān)系


1.通過數(shù)據(jù)庫遷移新建表+創(chuàng)建對應(yīng)模型
2.在新表中添加相應(yīng)字段用于建立關(guān)聯(lián)
3.通過模型類建立兩表之間的關(guān)聯(lián)
4.通過填充器寫入數(shù)據(jù)
5.通過關(guān)聯(lián)方法名作為動態(tài)屬性訪問模型實例

一對一,以useruser_profile為例。

# 1.一次完成創(chuàng)建表&對應(yīng)模型
$ php artisan make:model UserProfile -m 
# 2.在 user_profile 中新建 user_id 字段
# 3.建立關(guān)聯(lián),這里是在 User 模型類中定義關(guān)聯(lián)
public function profile()
{
    return $this->hasOne(UserProfile::class);
} 
# 5.訪問實例
$user = User::findOrFail(1);
$profile = $user->profile; 

# 建立相對的關(guān)聯(lián)關(guān)系,通過UserProfile 反查所屬的 User 模型
# 3.在 UserProfile 模型類定義與 User 模型的關(guān)聯(lián)
public function user()
{
    return $this->belongsTo(User::class);
} 
# 5.訪問
$profile = UserProfile::findOrFail(2);
$user = $profile->user; 

一對多,以 usersposts 表為例。

# 3.在 `User` 模型類中用 `hasMany` 方法建立關(guān)聯(lián)
public function posts()
{
    return $this->hasMany(Post::class);
}
# 5.訪問
$user = User::findOrFail(1);
$posts = $user->posts;

# 建立相對的關(guān)聯(lián)關(guān)系,比如在文章詳細(xì)頁或列表頁顯示作者信息
# 3.
public function user()
{
    return $this->belongsTo(User::class);
}
# 5.
$post = Post::findOrFail(29);
$author = $post->user;
# 還可以將 Post 模型中的關(guān)聯(lián)關(guān)系調(diào)方法名修改為 author
# 這樣可手動指定傳入的參數(shù)
# 3.
public function author()
{
    return $this->belongsTo(User::class, 'user_id', 'id', 'author');
}
# 5.
$author = $post->author;

hasOne 返回的是單個模型實例不一樣,hasMany 返回的是模型類集合。

多對多,以文章標(biāo)簽為例(posts、 tagspost_tags

# 2. 在中間表(post_tags)中新建 post_id 、tag_id 字段
# 3.在 Post 模型中定義其與 Tags 模型類的關(guān)聯(lián)關(guān)系
public function tags()
{
    return $this->belongsToMany(Tag::class, 'post_tags');
}
# 5.
$post = Post::findOrFail(1);
$tags = $post->tags;

# 建立相對的關(guān)聯(lián)關(guān)系
# 3. 在 Tag 模型類中建立與 Post 模型的關(guān)聯(lián)關(guān)系
public function posts()
{
    return $this->belongsToMany(Post::class, 'post_tags');
}
# 5.
$tag = Tag::with('posts')->where('name', 'ab')->first();
$posts = $tag->posts;

# 返回中間表字段
$post->pivot->tag_id 
# 返回額外字段,在建立關(guān)聯(lián)關(guān)系時手動指定
public function tags()
{
    return $this->belongsToMany(Tag::class, 'post_tags')->withPivot('user_id')->withTimestamps();
}

遠(yuǎn)層一對多關(guān)聯(lián),以 users、 postscountries為例

# 1.2.新建 country 模型及表,為 users 表新增 country_id 字段
# 3. 在 Country 模型類中定義關(guān)聯(lián)
public function posts()
{
    return $this->hasManyThrough(Post::class, User::class);
}  # 第一個參數(shù):關(guān)聯(lián)的模型類,第二個:中間借助的模型類
# 5.
$country = Country::findOrFail(1);
$posts = $country->posts;

# countries(user_id) - user(country_id) - posts(user_id)

一對一的多態(tài)關(guān)聯(lián),以 images 、userposts為例,讓用戶和文章共享與圖片的一對一關(guān)聯(lián)。

# 1.2.新建 Image 模型類及表
# 創(chuàng)建 imageable_id 和 imageable_type 兩個字段
# imageable_type 插入完整的類名以表類型 App\User 或 App\Post
$table->morphs('imageable'); 
# 3.
public function imageable()
{
    return $this->morphTo();
}
#5.
$image = Image::findOrFail(1);
$item = $image->imageable;

# 定義相對的關(guān)聯(lián)關(guān)系
# 3.
# 在 User 模型中定義與 Image 模型的關(guān)聯(lián)
public function image()
{
    return $this->morphOne(Image::class, 'imageable');
}
# 在 Post 模型中定義其與 Image 模型的關(guān)聯(lián)
public function image()
{
    return $this->morphOne(Image::class, 'imageable');
}
# 5.
$post = Post::findOrFail(1);
$image = $post->image;

(插眼)一對多的多態(tài)關(guān)聯(lián),新建 comment 評論模型類。

#3.
public function comments()
{
    return $this->morphMany(Comment::class, 'commentable');
}

模型關(guān)聯(lián)關(guān)系(下)


懶惰式加載

# 基于關(guān)聯(lián)查詢過濾模型實例

# 有結(jié)果過濾
$users = User::has('posts')->get(); # 獲取所有發(fā)發(fā)布過文章的用戶
$users = User::has('posts', '>', 1)->get(); # 過濾發(fā)布文章數(shù)量大于 1 的用戶
$users = User::has('posts.comments')->get(); # 過濾發(fā)布的文章有評論的用戶
$posts = Post::has('comments')->orHas('tags')->get(); # 過濾包含評論或標(biāo)簽的文章
$users = User::whereHas('posts', function ($query) {
    $query->where('title', 'like', '空空%');
})->get(); # 基于閉包函數(shù)定義查詢條件

# 無結(jié)果過濾
# 與 has/orHas 方法相對的 doesntHave/orDoesntHave 方法


# 不加載關(guān)聯(lián)模型的情況下統(tǒng)計關(guān)聯(lián)結(jié)果的數(shù)量
# 通過 Eloquent 提供的 withCount 方法
$post = Post::withCount('comments')->findOrFail(32); # 統(tǒng)計某篇文章的評論數(shù)

渴求式加載

$post = Post::with('author')->findOrFail(1);
$author = $post->author;

# 支持一次加載多個關(guān)聯(lián)模型(參數(shù)為對應(yīng)關(guān)聯(lián)方法名
$posts = Post::with('author', 'comments', 'tags')->findOrFail(1);
# 支持嵌套查詢
$post = Post::with('author.profile')->findOrFail(1);
# 指定要加載的字段
$post = Post::with('author:id,name')->findOrFail(1);
# 通過閉包傳入額外的約束條件
$post = Post::with(['comments' => function ($query) {
    $query->where('content', 'like', '空空%')
        ->orderBy('created_at', 'desc');
}])->where('id', '<', 5)->get();

懶惰渴求式加載
通過動態(tài)條件判斷進(jìn)行渴求式加載或者延遲加載,通過 load 方法實現(xiàn)。

$users = User::all();
$condition = true;
if ($condition) {
    $users->load('posts');
}
# 支持通過閉包傳遞額外的約束條件
$posts = Post::where('id', '<=', 3)->get();
$posts->load(['comments' => function ($query) {
    $query->where('content', 'like', 'Laravel學(xué)院%')
        ->orderBy('created_at', 'desc');
}]);

異步分頁


結(jié)合 Bootstrap 和 Vue 組件實現(xiàn)異步分頁功能,需要在后端定義好分頁數(shù)據(jù)獲取 API 接口。

# 定義后端 API 接口
# 1.在 PostController 中定義一個 fetch 方法用于異步獲取分頁數(shù)據(jù)
# 2.在 routes/api/php 中定義指向該控制器方法的 API 路由
# 測試API 接口,在瀏覽器中請求 http://blog.test/api/posts/fetch
# 3.在控制器的文章首頁列表方法 index 中,返回一個視圖用于渲染文章列表
# 創(chuàng)建文章列表視圖
# 4.新建 resources/views/post/index.blade.php,編寫視圖代碼
# 創(chuàng)建 Vue 分頁組件
# 5.新建 resources/js/components/PaginationComponent.vue,初始化代碼并在 resources/js/app.js 中注冊組件
# 6. npm run dev編譯前端資源
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容