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

路由進階使用


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進階篇

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)建器進行增刪改查
$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個進行處理辫呻,將用戶名依次放到 $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)建時間進行逆序排序
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é)果進行過濾
    ->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)表名是 postsPostTag 對應(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ù)庫之前進行一定處理滿足需求后再存(修改器
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画髓、 tags掘剪、 post_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)夺谁,以 usersposts肉微、 countries為例

# 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)條件判斷進行渴求式加載或者延遲加載,通過 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)系作者
  • 序言:七十年代末烫止,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子戳稽,更是在濱河造成了極大的恐慌馆蠕,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惊奇,死亡現(xiàn)場離奇詭異互躬,居然都是意外死亡,警方通過查閱死者的電腦和手機颂郎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門吼渡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乓序,你說我怎么就攤上這事寺酪≈鄣欤” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵房维,是天一觀的道長沼瘫。 經(jīng)常有香客問我,道長咙俩,這世上最難降的妖魔是什么耿戚? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮阿趁,結(jié)果婚禮上膜蛔,老公的妹妹穿的比我還像新娘。我一直安慰自己脖阵,他們只是感情好皂股,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著命黔,像睡著了一般呜呐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悍募,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天蘑辑,我揣著相機與錄音,去河邊找鬼坠宴。 笑死洋魂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喜鼓。 我是一名探鬼主播副砍,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼庄岖!你這毒婦竟也來了铣卡?” 一聲冷哼從身側(cè)響起守屉,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤入篮,失蹤者是張志新(化名)和其女友劉穎垢袱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硼控,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡刘陶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了牢撼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匙隔。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熏版,靈堂內(nèi)的尸體忽然破棺而出纷责,到底是詐尸還是另有隱情捍掺,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布再膳,位于F島的核電站挺勿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏喂柒。R本人自食惡果不足惜不瓶,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灾杰。 院中可真熱鬧蚊丐,春花似錦、人聲如沸艳吠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昭娩。三九已至凛篙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間题禀,已是汗流浹背鞋诗。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留迈嘹,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓全庸,卻偏偏與公主長得像秀仲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子壶笼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348