Laravel 中一些常用的小技巧,額,說不定你就用上了。。。
1.側欄
網站一般都有側欄,用來顯示分類,標籤,熱門文章,熱門評論啥的,但是這些側欄都是相對獨立的模組,如果在每一個引入側欄的檢視中都單獨匯入與檢視有關的資料的話,未免太冗餘了。。。所以最佳的做法是:新建一個widgets
檢視資料夾,再利用Laravel 的ViewComposers
單獨為側欄繫結資料,這樣側欄就可以隨便引入而不用關心資料是否繫結啦~~~
舉個栗子?拿最常用的分類側欄來說,在resources/views/widgets
下新建你的分類側欄檢視檔案categories.blade.php
:
新建app/Http/ViewComposers
資料夾,然後建立CategoriesComposer.php
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php namespace App\Http\ViewComposers; use App\Http\Repositories\CategoryRepository; use Illuminate\View\View; class CategoriesComposer { public function __construct(CategoryRepository $categoryRepository) { $this->categoryRepository = $categoryRepository; } public function compose(View $view) { $categories = $this->categoryRepository->getAll()->reject(function ($category) { return $category->posts_count == 0; }); $view->with('categories', $categories); } } |
再在app/Providers
資料夾下新建ComposerServiceProvider.php
檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\View; class ComposerServiceProvider extends ServiceProvider { public function boot() { View::composer('widget.categories', 'App\Http\ViewComposers\CategoriesComposer'); } public function register(){} } |
最後別忘了在config/app.php
中的providers
陣列中新增AppProvidersComposerServiceProvider::class
啊。好了,現在你可以隨時隨地@include('widget.categories')
了。對了,要善於在ViewComposer
中利用Collection
的強大方法進行資料處理么~~
2.善用路由別名
Laravel 最讓人喜歡的地方之一是可以給路由起一個別名,比如:
1 2 3 |
Route::get('user/profile', 'UserController@showProfile')->name('user.profile'); // 等價於: Route::get('user/profile', ['uses' => 'UserController@showProfile' , 'as' => 'user.profile']);; |
然後,就可以在試圖中就可以使用route()
方法引用了:
1 2 |
// 例如: <a href="{{ route('user.profile') }}">lufficc</a> |
因為一個普通的專案路由至少也得有幾十個,如果使用url()
方法的話,你不但要記住具體的路由,更麻煩的是如果你將來想要改變某個路由(比如把'user/profile'
改為'u/profile'
,或者加個字首啥的),必須改變所有相關的檢視檔案,這。。。這。。。不敢相信,而使用命名路由的話,只要命名不變,毫不受影響。
所以檢視檔案中儘量避免使用url()
方法,為每一個路由命名,一個預設的命名規則為:資源名稱.或者
,如post.show
,image.upload
。
3.全域性動態設定
僅僅是.env
的配置還無法滿足我們的需求,有時我們需要可以在後臺動態的進行一些設定,比如網站的標題,網站的背景圖片或者是否允許評論等等。那麼實現這個的最佳實踐是什麼?
熟悉wordpress的同學知道,wordpress可以進行很多自定義,因為wordpress有一張鍵值對資料庫表,它就是靠這個實現個性化的。因此我們也可以參考這種思路,增加一個鍵值對錶,以Xblog為例子,新建一個maps
表:
1 2 3 4 5 6 |
Schema::create('maps', function (Blueprint $table) { $table->increments('id'); $table->string('key')->unique(); $table->string('tag')->index(); $table->text('value')->nullable(true); }); |
maps
表的作用就是實現鍵值對key-value
儲存,tag
的是為了可以有一個分類。然後後臺進行儲存的話,不要寫死,這樣就可以隨時在變單中新增設定而無需更改程式碼:
1 2 3 4 5 6 7 8 9 |
$inputs = $request->except('_token'); foreach ($inputs as $key => $value) { $map = Map::firstOrNew([ 'key' => $key, ]); $map->tag = 'settings'; $map->value = $value; $map->save(); } |
注意firstOrNew
的用法:如果不存在這個選項我們就新增一個並儲存,否則就更新它。然後我們就可以在檢視中隨便增加任意多個表單了(或者也可以用js動態生成表單)。有了資料,怎麼在檢視中利用呢?利用ViewComposer
,新建一個SettingsComposer.php
,然後將查詢的資料以陣列的形式傳遞給檢視:
1 2 3 4 5 6 7 8 9 10 |
//在SettingsComposer.php的compose方法中繫結資料 public function compose(View $view) { $settings = Map::where('tag', 'settings')->get(); $arr = []; foreach ($settings as $setting) { $arr[$setting->key] = $setting->value; } $view->with($arr); } |
然後就可以在檢視中隨便引用了,如你表單新增加了一個description
1 |
<input type="text" name="description" value="{{ $description or ''}}"> |
然後就可以在任何檢視引用了:{{ $description or ''}}
。另外還可以繫結一個單例Facades
到容器,這樣就可以在程式碼中隨時獲取配置資訊啦~~~
比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//1.註冊 public function register() { $this->app->singleton('XblogConfig', function ($app) { return new MapRepository(); }); } //2.註冊Facade class XblogConfig extends Facade { public static function getFacadeAccessor() { return 'XblogConfig'; } } //3.新增到aliases陣列 'aliases' => [ ***************** 省略 ************************* 'XblogConfig' => App\Facades\XblogConfig::class, ], //4.愉快的使用,可爽 $page_size = XblogConfig::getValue('page_size', 7); |
4.資料庫查詢
怎麼統計一篇文章有多少評論?最快的方法是:
1 |
$post = Post::where('id',1)->withCount('comments')->first(); |
這樣$post
變數就有一個屬性comments_count
了:
1 |
$post->comments_count; |
如果想獲取點贊數大於的100的評論個數怎麼辦?這樣:
1 2 3 |
$post = Post::where('id',1)->withCount('comments',function($query){ $query->where('like', '>', 100); })->first(); |
簡單吧~~
5.多型關聯
文章可以有評論,頁面可以有評論,評論也可以有評論,但是總不能建三張評論表吧?如果自己寫條件判斷也太麻煩了吧。。。Laravel的多型關聯上場了!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//1.第一步在Comment模型中說明我是可以多型的 public function commentable() { return $this->morphTo(); } //2.在想要評論的模型中增加comments方法, public function comments() { return $this->morphMany(Comment::class, 'commentable'); } //3.使用,就像普通的一對多關係一樣: $model->comments; |
原理很簡單,comments
表中增加兩個列就行:
1 2 3 4 5 6 7 8 |
Schema::create('comments', function (Blueprint $table) { ***************省略******************* $table->morphs('commentable'); //等價於 $table->integer('commentable_id')->index(); $table->string('commentable_type')->index(); ****************省略****************** }); |
然後 laravel 會自動維持這些關係。注意,儲存的評論的時候是有小技巧的,你的表單中至少要傳兩個引數:commentable_id
和commentable_type
:
1 2 3 4 5 6 7 8 9 |
$comment = new Comment(); $commentable_id = $request->get('commentable_id'); //commentable_type取值例如:AppPost,AppPage等等 $commentable = app($request->get('commentable_type'))->where('id', $commentable_id)->firstOrFail(); ****************省略****************** $commentable->comments()->save($comment); |
儲存評論的時候並不知道是誰的評論,而是使用容器根據commentable_type
生成一個模型例項,這樣也就和具體的模型解耦了,你可以讓任何東西可以評論,而不需要修改程式碼。
6.快取優化相關
如果你想要在.env
檔案中新增自己的配置,記住一定要在config
資料夾下某個配置檔案的陣列中新增對應的。記住,除了config
資料夾下的配置檔案,永遠不要在其它地方使用env
函式,因為部署到線上時,配置檔案快取(php artisan config:cache
)後,env
函式無法獲得正確的值。
另外注意的是,路由檔案中儘量不使用閉包函式,統一使用控制器,因為快取路由的時候php artisan route:cache
,無法快取閉包函式。
7.Redis
如果你快取使用Redis,session
也使用了Redis,佇列已使用了Redis,這樣沒問題,速度很快,但是!!當你執行php artisan cache:clear
清除快取時,會把你的登入資訊清除,也會把佇列清除。。。這就不優雅了。解決辦法很簡單,為它們分配不同的連線即可。
首先在configdatabase.php
中增加連線,注意database
序號:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
'redis' => [ 'cluster' => false, 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], 'session' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 1, ], 'queue' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 2, ], ], |
然後分別為session
和queue
更換連線:
1 2 3 4 5 6 7 8 9 10 |
//queue.php中的connections陣列中: 'redis' => [ 'driver' => 'redis', 'connection' => 'queue', 'queue' => 'default', 'retry_after' => 90, ], //session.php中的connection選項: 'connection' => 'session', |
這樣他們就互不相干了~~