學(xué)習(xí)筆記:《Laravel5.3》

過去做事情急,什么東西拿起來就用,不喜歡進(jìn)行系統(tǒng)性的學(xué)習(xí),造成在使用過程中的錯(cuò)誤和低效,現(xiàn)在感覺自己耐心多了,用之前先系統(tǒng)的看一下文檔,再接著用。

Laravel 是“小丑魚”項(xiàng)目技術(shù)團(tuán)隊(duì)共同確定下來的 PHP 程序框架,其近幾年的發(fā)展異常迅猛,已經(jīng)蓋過了 YII 和 Symfony 的風(fēng)頭。Laravel 的發(fā)起人 Taylor Otwell 在 Blog 中說自己的偶像是 Symfony 的創(chuàng)始人 Fabien Potencier:《PHP Developers Who Have Inspired Me》

Laravel 需要使用 composer 安裝,然后安裝 composer 本身又需要命令行支持https翻墻(后來知道其實(shí)下載也可以),https翻墻需要裝 icu4c,icu4c 需要安裝 brew,好在 ruby 已經(jīng)系統(tǒng)安裝了,不然這個(gè)循環(huán)還會(huì)繼續(xù)下去。Laravel 最新版本對 PHP 版本的要求也比較高,要求 PHP >= 5.6.4,為此專門把本地 PHP 版本升了級。

安裝:

  1. 先安裝好 Composer
  2. 全局安裝 laravel/installer,一個(gè) laravel 的安裝工具
    composer global require "laravel/installer"
  3. 初始一個(gè) laravel 的項(xiàng)目,然后就可以開始運(yùn)行了
    $HOME/.composer/vendor/bin new project_name
  4. 建立 .env 文件
    cp .env.example .env
  5. 設(shè)置 APP_KEY
    ./artisan key:generate
  6. 設(shè)置權(quán)限(正式環(huán)境不要這么操作)
    chmod -R 777 .

以下是閱讀官方文檔做的記錄,基于5.2版本:

目錄結(jié)構(gòu)

這里解釋的非常清楚:https://laravel-china.org/docs/5.4/structure

在 Laravel 的開發(fā)過程中會(huì)用到許多不同類型的包管理工具,新生成很多的文件,這里簡單說明一下:

composer.json 是 composer 的配置文件
/vendor 目錄存放被 composer 安裝的文件

package.json 是 nodejs 的配置文件
/node_modules 目錄存放被 npm 安裝的文件

bower.json 是 bower 的配置文件
.bowerrc 文件中設(shè)置了被 bower 安裝的文件,一般設(shè)置為 /resources/assets/bower

gulpfile.js 是 gulp 的配置文件

框架核心結(jié)構(gòu)

Service Container:
管理依賴注入(dependency injection)的容器工具,《嘮嘮依賴注入》 《嘮嘮Service Container》 兩篇文章里面解釋的比較清晰。

Service Providers:
包含了 Service Container、事件監(jiān)聽(event listeners)、中間件(middleware)、路由(routes)的整套實(shí)現(xiàn)機(jī)制的類。
// Laravel Framework Service Providers... Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Cookie\CookieServiceProvider::class, Illuminate\Database\DatabaseServiceProvider::class, Illuminate\Encryption\EncryptionServiceProvider::class, Illuminate\Filesystem\FilesystemServiceProvider::class, Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, // Application Service Providers... App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class,

HTTP層:

Routing
Laravel 非常尊重 CRUD,所以可以在表單里面添加:
<input type="hidden" name="_method" value="PUT">

路由中傳遞的 id 值可以根據(jù)名字直接返回帶有了數(shù)據(jù)字段的 model(感覺這個(gè)有點(diǎn)太過于智能了):
Route::get('api/users/{user}', function (App\User $user) { return $user->email; });

Laravel 5.2 開始取消了 Route::controller() 這個(gè)方法,不能再方便得使用:

Route::controller('user', 'UserController');

官方文檔中的解釋是:

The following features are deprecated in 5.2 and will be removed in the 5.3 release in June 2016:
Implicit controller routes using Route::controller
have been deprecated. Please use explicit route registration in your routes file. This will likely be extracted into a package.

可能是為了讓路由的定義更加的清晰化

Middleware
類似于 Symfony 的 FIlter,屬于一個(gè)請求從 HTTP 層 進(jìn)入到 APP 層,以及從 APP 層出去到 HTTP 層過程中可以添加處理的部分。

CSRF Protection
在表單中添加:
{{ csrf_field() }}
或者
<input type="hidden" name="_token" value="{{ csrf_token() }}">
然后 VerifyCsrfToken 這個(gè)中間件便會(huì)自動(dòng)處理 CSRF,對于 AJAX 請求的保護(hù),則可以在 meta 中插入:
<meta name="csrf-token" content="{{ csrf_token() }}">
再配合一段 JS 的程序來自動(dòng)實(shí)現(xiàn):
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });

Controllers
如果路由中沒有指定某個(gè)具體的 Controller 方法,則指向一下叫做 __envoke() 的方法:
public function __invoke($id) { return view('user.profile', ['user' => User::findOrFail($id)]); }

中間件經(jīng)常在 Controller 的構(gòu)造方法中被指定:
public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); }

Controller 中有一套封裝好的 CRUD,叫做 Resource Routes,感覺比較重,不大敢用。

Controller 方法的第一個(gè)參數(shù)支持 Service Container,還是蠻有意思的,構(gòu)造函數(shù) __construct() 的第一個(gè)參數(shù)也支持,使用 Service Container 的方式是利用的 PHP 最新版本的新語法,在實(shí)踐中看看會(huì)出現(xiàn)怎么樣的運(yùn)用機(jī)會(huì),這種運(yùn)用反射機(jī)制和 type-hint 結(jié)合而出現(xiàn)的使用方式,真的是喪心病狂......

Requests & Responses
Laravel 的 Requests & Responses 遵循著 PSR-7 standard 的標(biāo)準(zhǔn),對上傳和下載也做了相應(yīng)的封裝,東西比較多,這個(gè)具體使用的時(shí)候查文檔

Validation
有一個(gè)叫做 bail 的參數(shù)可以幫助只返回首個(gè)驗(yàn)證不通過的信息:
$this->validate($request, [ 'title' => 'bail|required|unique:posts|max:255', 'body' => 'required', ]);

View 和 Template

View
View 可以進(jìn)行判斷:
if (View::exists('emails.customer')) { // }

如果你希望每個(gè) Controller 中都可以共享一些值,也可以有方法可以實(shí)現(xiàn),但是會(huì)有人記得用嗎?
public function boot() { View::share('key', 'value'); }

View Composers
如果你希望不同的 Controller 中的 View 可以共享一些數(shù)據(jù),那么就可以引入 View Composers 的機(jī)制,不過個(gè)人感覺實(shí)踐中沒有特別的必要使用這個(gè)機(jī)制,太私人的業(yè)務(wù)邏輯歸屬會(huì)讓代碼不易維護(hù)

Blade Templates
Laravel 提供的一套輕量級的模板引擎,未來的架構(gòu)會(huì)越來越趨向于前后端的分離,加之 PHP 語言本身具有較強(qiáng)的模板特性,內(nèi)置一套輕量級的模板引擎是非常聰明的解決方案。

涉及前端部分

Laravel 結(jié)合使用了 Bootstrap 和 Vue 作為前端解決方案,然后提供了一個(gè)叫做 Laravel Elixir 的工具來進(jìn)行前端 JS 和 CSS 的編譯,同時(shí)這個(gè)編譯過程支持 Less、Sass、Stylus、Plain CSS 這些 CSS 的同時(shí)編譯,也支持 Webpack、Rollup、JavaScript 的結(jié)合編譯。Laravel Elixir 本身是對 Gulp 的封裝,而 Gulp 是基于 node.js 他們家的 npm,所以這個(gè)解決方案的安裝過程也是喪心病狂,一路上 node.js、npm、Gulp、Laravel Elixir 安裝完,等到真正使用的時(shí)候不知道還會(huì)遇到多少問題,成本啊!

因?yàn)?Laravel Elixir 基于 Gulp,所以在編譯的時(shí)候可以直接用 Gulp 的命令行工具:
gulp // 編譯命令 gulp watch // 只要 CSS 或者 JS 文件修改過了,就會(huì)自動(dòng)編譯

余下的就是看 Bootstrap 和 Vue 的文檔了

涉及安全部分

Laravel 提供了一個(gè) Auth 靜態(tài)類存放權(quán)限安全相關(guān)的代碼,提供了 Gate 靜態(tài)類處理認(rèn)證相關(guān)的內(nèi)容

Authentication
Laravel 對 Authentication 做了全局統(tǒng)籌,不僅僅注冊好了路由,而且運(yùn)行 php artisan make:auth 可以看到一個(gè)腳手架搭建好的小系統(tǒng),方便學(xué)習(xí):
// Authentication Routes... $this->get('login', 'Auth\AuthController@showLoginForm'); $this->post('login', 'Auth\AuthController@login'); $this->get('logout', 'Auth\AuthController@logout'); // Registration Routes... $this->get('register', 'Auth\AuthController@showRegistrationForm'); $this->post('register', 'Auth\AuthController@register'); // Password Reset Routes... $this->get('password/reset/{token?}', 'Auth\PasswordController@showResetForm'); $this->post('password/email', 'Auth\PasswordController@sendResetLinkEmail'); $this->post('password/reset', 'Auth\PasswordController@reset');

在數(shù)據(jù)安全方面,Laravel 提供了一套稱為 Policy 的解決機(jī)制,Policy 機(jī)制可以在 Methods、Models、Filters、Authorizing Actions、Middleware、Controller Helpers、Blade Templates中進(jìn)行使用

文檔中提到了涉及 Vue 的一套 API Authentication 解決方案,因?yàn)閷?Vue 還不夠了解,這塊先放過,等學(xué)會(huì)了 Vue 以后再回過頭來看這塊的內(nèi)容

Laravel 提供了一個(gè) encrypt helper 協(xié)助加密保護(hù),使用 OpenSSL 和 AES-256-CBC cipher,反正都封裝好了,只要用就是了

Laravel 提供了一個(gè) Hash 靜態(tài)類產(chǎn)生和匹配用戶密碼,也是封裝好了,用就可以

一些零碎知識

Event Broadcasting
Laravel 提供了很詳細(xì)的通訊解決方案,支持 Pusher、Redis、Socket.IO、Log 等等的驅(qū)動(dòng)方案,提供了一個(gè)叫做 Laravel Echo 的 Javascript 工具包在前端部分進(jìn)行支持,這塊文檔詳細(xì)的提供了一個(gè)示例,等用到的時(shí)候可以參考

Cache
提供了一個(gè) Cache 靜態(tài)類操作緩存,支持 Memcached、Redis、文件、數(shù)據(jù)庫緩存

Events & Listeners
這個(gè)應(yīng)該是來源于 Symfony 的一套程序監(jiān)聽機(jī)制,但是感覺在大型系統(tǒng)中這樣的方式會(huì)把業(yè)務(wù)邏輯搞的比較混亂,所以一直沒有大規(guī)模使用過,但是前面 Event Broadcasting 的文檔中強(qiáng)調(diào)了其重要性,可能在通訊解決方案中這樣的監(jiān)聽機(jī)制是需要的,具體在使用的時(shí)候去理解

文件系統(tǒng)使用的 Flysystem,Storage 這個(gè)靜態(tài)類封裝了文件管理的全部功能,遠(yuǎn)程(亞馬遜A3、Rackspace等)、本地等等,各種文件相關(guān)的操作需求應(yīng)有盡有

郵件機(jī)制使用的是 SwiftMailer,SwiftMailer 本身是對 SMTP, Mailgun, SparkPost, Amazon SES, PHP's mail function, sendmail 等的封裝,出自 SensioLabs,所以品質(zhì)有保障

Notifications
消息機(jī)制是指給用戶發(fā)提醒郵件、SMS信息、Slack、網(wǎng)頁上的提醒信息等等,使用的 Notification 靜態(tài)類進(jìn)行了所有相關(guān)功能的封裝

Queues
隊(duì)列機(jī)制 Laravel 也提供了詳細(xì)的支持,包括 Beanstalkd, Amazon SQS, Redis, 本地?cái)?shù)據(jù)庫等等

這些零碎的知識,都是對一些較小應(yīng)用場景的功能封裝,對于這樣的封裝,最怕的就是不完善然后用戶會(huì)跳過封裝直接用相關(guān)的接口,維護(hù)起來也比較困難,所以無論過去封裝成 PHP 組件,或者是成為某些框架的插件,都很難取得成功,更別提像 Laravel 這樣包含在框架的核心代碼里面,Laravel 能這么做,我想有一個(gè)原因是 composer 的出現(xiàn)讓代碼更高效的復(fù)用成為一種可能,即時(shí)是 Laravel 的核心庫,也可以方便的和別的項(xiàng)目共享

數(shù)據(jù)庫相關(guān)

Query Builder:Laravel 提供的一套數(shù)據(jù)庫操作方法,基于 DB 這個(gè) Facade 靜態(tài)類,這里有詳細(xì)的關(guān)于這個(gè)方法的接口說明:
https://laravel.com/api/5.3/Illuminate/Database/Query/Builder.html

Migrations:等到項(xiàng)目的業(yè)務(wù)邏輯到達(dá)一定的規(guī)模,會(huì)有 Migrations 方面的需求,在 Laravel 中體現(xiàn)為 Schema 這個(gè) Facade 靜態(tài)類

Eloquent ORM:Laravel 提供的一套 ActiveRecord 實(shí)現(xiàn),有一些很有趣的機(jī)制:

Collections:提供了一整套強(qiáng)大的方法幫助檢索返回?cái)?shù)據(jù)的處理,很多的有用方法都支持 Lamda 表達(dá)式作為參數(shù),非常有效的提升了代碼的可讀性。

Accessors & Mutators:在 get 和 set 數(shù)據(jù)的時(shí)候分別加上了一層回調(diào)處理,對業(yè)務(wù)邏輯的分離非常有幫助。

Date Mutators:實(shí)現(xiàn)一個(gè) Carbon 的實(shí)例:
https://github.com/briannesbitt/Carbon
將類屬性 $dates 中設(shè)定的相關(guān)字段自動(dòng)轉(zhuǎn)換成一個(gè) Carbon 對象,可以調(diào)用所有 Carbon 中的相關(guān)方法。

Attribute Casting:使用類屬性 $casts 可以方便得對 get 到的字段數(shù)據(jù)進(jìn)行屬性設(shè)定,可以進(jìn)行一層類型轉(zhuǎn)換,可以設(shè)置的值有:integer, real, float, double, string, boolean, object, array, collection, date, datetime, timestamp

Serialization:幫助查詢數(shù)據(jù)在格式處理時(shí)候的兩個(gè)方法 toArray() 和 toJson(),兩個(gè)協(xié)調(diào)相應(yīng)字段顯示與否的類屬性 $hidden 和 $visible,以及額外增加顯示信息的 $appends 類屬性

pivot:在處理 ManyToMany 關(guān)系的時(shí)候,對于中間表專門提供的一個(gè)屬性和方法協(xié)助方便處理

Mass Assignment:提供了防止字段被錯(cuò)誤插入數(shù)據(jù)的兩個(gè)屬性 $fillable 和 $guarded

在插入數(shù)據(jù)的時(shí)候 firstOrCreate(), firstOrNew() 在提供一些列的查詢條件后沒有任何匹配結(jié)果,則直接進(jìn)行插入

findOrFail(), firstOrFail() 如果查詢沒有任何的結(jié)果,就拋出一個(gè) ModelNotFoundException

除了 One To One、One To Many、Many To Many 以外,laravel還提供了 Has Many Through(遠(yuǎn)層一對多關(guān)聯(lián):跨一個(gè)表進(jìn)行一對多關(guān)聯(lián))、Polymorphic Relations(多態(tài)關(guān)聯(lián):某個(gè)字段多態(tài)關(guān)聯(lián)不同的外表)、Many To Many Polymorphic Relations(多態(tài)的多對多關(guān)聯(lián))

Eager Loading:關(guān)聯(lián)查詢的時(shí)候提高效率的機(jī)制,使用 with() 方法實(shí)現(xiàn),傳 Lamda 表達(dá)式的方法也是很贊:
$users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get();

Soft Deleting:Laravel 提供了整套的 Soft Deleting 解決方案,當(dāng)然你不希望一個(gè)數(shù)據(jù)真正的從數(shù)據(jù)庫刪除的時(shí)候

Query Scopes:查詢作用域,將某些查詢的條件綁定到某個(gè) Model 上,比如 Soft Deleting 的時(shí)候,或者丟棄歷史數(shù)據(jù)的時(shí)候,Query Scopes 就非常能幫得上

chunk:當(dāng) crontab 操作的時(shí)候遇到30秒時(shí)間限制的時(shí)候,就可以用 Laravel 提供的這個(gè) chunk() 方法來解決:
http://laraveldaily.com/process-big-db-table-with-chunk-method/

aggregate methods:count, max, min, avg, and sum,對查詢結(jié)構(gòu)數(shù)據(jù)進(jìn)行操作的簡單方法

Seeding:一套偽造測試數(shù)據(jù)的方法,做單元測試之類的時(shí)候,會(huì)非常的有用

附件

Facades:一套靜態(tài)類的基類接口,提供了 Laravel 整套的靜態(tài)類標(biāo)準(zhǔn)解決方案,便于靜態(tài)類全局使用
'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class

Contracts:前面的 Facades 是系統(tǒng)提供的一套靜態(tài)類,但是如果你希望可以自定義這些功能的話,可以用 Contracts 來實(shí)現(xiàn),Contracts 的作用是為你提供好了解耦的機(jī)制,方便自定義的時(shí)候直接套用,也是因?yàn)?Contracts 的存在,可以方便的找到很多現(xiàn)成的代碼可以直接使用(防止第三方提供的代碼具有耦合性)

Contract 對應(yīng)的 Facade
Illuminate\Contracts\Auth\Factory Auth
Illuminate\Contracts\Auth\PasswordBroker Password
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Broadcasting\Broadcaster
Illuminate\Contracts\Cache\Repository Cache
Illuminate\Contracts\Cache\Factory Cache::driver()
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Encryption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud
Illuminate\Contracts\Filesystem\Factory File
Illuminate\Contracts\Filesystem\Filesystem File
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Logging\Log Log
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Queue\Factory Queue::driver()
Illuminate\Contracts\Queue\Queue Queue
Illuminate\Contracts\Redis\Database Redis
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Support\Arrayable
Illuminate\Contracts\Support\Jsonable
Illuminate\Contracts\Support\Renderable
Illuminate\Contracts\Validation\Factory Validator::make()
Illuminate\Contracts\Validation\Validator
Illuminate\Contracts\View\Factory View::make()
Illuminate\Contracts\View\View -

Collections:對數(shù)組操作進(jìn)行封裝的一套方法,保留了 PHP 數(shù)組操作的巨大有點(diǎn),同時(shí)又滿足了方法的調(diào)用需求,不羅列了,可以直接看文檔

Helper Functions:70-80個(gè)左右的 Laravel 封裝的函數(shù),又一次對數(shù)組、字符串、Url等等的操作進(jìn)行了擴(kuò)展,看來 PHP 語言的函數(shù)總量,還是達(dá)不到 Laravel 的需求,在使用的過程中可以根據(jù)需求自己挖礦,不羅列了,可以直接看文檔

使用備忘(細(xì)節(jié))

Cookie:

Cookie::queue('userId', 3, 1440);
echo Cookie::get('userId');
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容