* * * * *
[TOC]
## 從 5.3 升級到 5.4.0
#### 預計升級耗時: 1-2 小時
> {note} 我們盡量羅列出每一個不兼容的變更。但因為其中一些不兼容變更只存在于框架很不起眼的地方,事實上只有一小部分會真正影響到你的應用程序。
### 更新依賴
在?`composer.json`?文件中將你的?`laravel/framework`?更新為?`5.4.*`。 此外, 你應該更新你的?`phpunit/phpunit`?依賴關系到?`~5.7`。
#### 刪除編譯的服務文件
如果存在,你可以刪除?`bootstrap/cache/compiled.php`?文件。 它不再被框架使用。
#### 刷新緩存
升級所有軟件包之后,你應該運行?`php artisan view:clear`?來避免與刪除?`Illuminate\View\Factory::getFirstLoop()`?相關的 Blade 錯誤。此外,你需要運行?`php artisan route:clear`?來刷新路由緩存。
#### Laravel Cashier
Laravel Cashier 已經兼容 Laravel 5.4。
#### Laravel Passport
為了兼容 Laravel 5.4 和?[Axios](https://github.com/mzabriskie/axios)?JavaScript 庫,Laravel Passport 已經發布了?`2.0.0`?。如果你是從 Laravel 5.3 升級,并使用了預置的 Passport Vue 組件,你應該確保 Axios 庫在你的應用程序中作為?`axios`?全局可用。
#### Laravel Scout
Laravel Scout?`3.0.0`?已經發布,以提供與 Laravel 5.4 的兼容性。
#### Laravel Socialite
Laravel Socialite?`3.0.0`?已經發布,以提供與 Laravel 5.4 的兼容性。
#### Laravel Tinker
為了繼續使用?`tinker`?Artisan 命令,你還應該安裝?`laravel/tinker`?包:
~~~
composer require laravel/tinker
~~~
一旦軟件包被安裝,你應該添加?`Laravel\Tinker\TinkerServiceProvider::class`?到?`config/app.php`?配置文件中的?`providers`數組。
#### Guzzle
Laravel 5.4 需要 Guzzle 6.0或者更高版本。
### 授權
#### `getPolicyFor`?方法
在之前的版本中,調用?`Gate::getPolicyFor($class)`?方法的時候,如果沒有找到對應的 policy,會拋出異常。 現在, 該方法在給定類中找不到policy的時候會返回?`null`。 如果你直接調用這個方法,請確保你在重構代碼中新增了對?`null`的檢查:
~~~
$policy = Gate::getPolicyFor($class);
if ($policy) {
// code that was previously in the try block
} else {
// code that was previously in the catch block
}
~~~
### Blade
#### `@section`?轉碼
在 Laravel 5.4,傳遞給 section 的內聯內容會自動進行轉碼:
~~~
@section('title', $content)
~~~
如果你想要在 section 中渲染原生內容,你必須使用傳統的「長形式」聲明該 section。
~~~
@section('title')
{!! $content !!}
@stop
~~~
### 引導程序
如果你在 HTTP 或 Console 啟動類中手動覆蓋了?`$bootstrappers`?數組,需要將?`DetectEnvironment`?重命名為?`LoadEnvironmentVariables`。
### 廣播
#### 頻道模型綁定
在 Laravel 5.3 中定義頻道名稱占位符時,使用?`*`?字符。在 Laravel 5.4 中, 你應該使用?`{foo}`?風格來定義這些占位符,如路由:
~~~
Broadcast::channel('App.User.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
~~~
### 集合
#### `every`?方法
`every`?方法的功能被合并到?`nth`?方法中以匹配被 Lodash 定義的方法名。
#### `random`?方法
調用?`$collection->random(1)`?現在會返回一個包含單個item的新的集合實例。在之前版本中,這個方法會返回單個對象。如果沒有提供參數,該方法將只返回單個對象。
### 容器
#### 別名 via?`bind`?/?`instance`
在之前的 Laravel 版本中,你可以將數組作為第一個參數傳遞給?`bind`?或者?`instance`?方法來注冊別名:
~~~
$container->bind(['foo' => FooContract::class], function () {
return 'foo';
});
~~~
然而,這種行為已經在 Laravel 5.4 中刪除。要注冊別名,你應該使用?`alias`?方法:
~~~
$container->alias(FooContract::class, 'foo');
~~~
#### 使用 \ 綁定類
將不再支持通過帶有 \ 的類名綁定類到容器。因為該功能需要在底層容器中進行大量的字符串格式化調用。取而代之的,只需要通過下面這種不帶 \ 的方式綁定即可:
~~~
$container->bind('Class\Name', function () {
//
});
$container->bind(ClassName::class, function () {
//
});
~~~
#### `make`?方法參數
容器的?`make`?方法不再接受第二個數組參數,因為該特性表明了代碼的壞味道。我們需要以更加直觀的方式來構造對象。
#### 解決回調
容器的?`resolving`?和?`afterResolving`?方法現在必須提供一個類名或綁定鍵作為方法的第一個參數:
~~~
$container->resolving('Class\Name', function ($instance) {
//
});
$container->afterResolving('Class\Name', function ($instance) {
//
});
~~~
#### `share`?方法已刪除
`share`?方法已經從容器中刪除。這是一個遺留的方法,多年未被列出來。如果你使用這個方法,你應該開始使用?`singleton`?方法:
~~~
$container->singleton('foo', function () {
return 'foo';
});
~~~
### 控制臺
#### The?`Illuminate\Console\AppNamespaceDetectorTrait`?Trait
如果你直接引用?`Illuminate\Console\AppNamespaceDetectorTrait`?trait,更新你的代碼替換為?`Illuminate\Console\DetectsApplicationNamespace`。
### 數據庫
#### 自定義連接
如果你之前為?`db.connection.{driver-name}`?綁定了一個服務容器綁定以便解析自定義數據庫連接實例,現在需要在?`AppServiceProvider`?的?`register`?方法中使用?`Illuminate\Database\Connection::resolverFor`?方法:
~~~
use Illuminate\Database\Connection;
Connection::resolverFor('driver-name', function ($connection, $database, $prefix, $config) {
//
});
~~~
#### Fetch 模式
Laravel不再支持在配置文件中定制PDO 「fetch mode」 的功能。取而代之,?`PDO::FETCH_OBJ`?一直可以使用。如果你仍然想要為你的應用程序自定義提取模式,你可以監聽新的?`Illuminate\Database\Events\StatementPrepared`?事件:
~~~
Event::listen(StatementPrepared::class, function ($event) {
$event->statement->setFetchMode(...);
});
~~~
### Eloquent
#### 日期轉換
日期轉換?`date`?現在會將日期轉化為?`Carbon`?對象并調用該對象上的?`startOfDay`?方法,如果你想保留日期的時間部分,需要使用?`datetime`?轉換。
#### 外鍵約束
在定義關聯關系的時候如果外鍵沒有被顯式指定,Eloquent 將會使用關聯模型的表名和主鍵名來構建外鍵。這適用于大多數應用,這不是行為的改變。例如:
~~~
public function user()
{
return $this->belongsTo(User::class);
}
~~~
就像以前的 Laravel 版本一樣,這種關系通常使用?`user_id`?作為外鍵。但是,如果你重寫?`User`?模型的?`getKeyName`?方法,情況就會變得不一樣,例如:
~~~
public function getKeyName()
{
return 'key';
}
~~~
在這種情況下,Laravel 會以你自定義的主鍵名為準,外鍵名將會是?`user_key`?而不是?`user_id`。
#### 一對一 / 多的?`createMany`
`hasOne`?or?`hasMany`?關系的?`createMany`?方法現在返回一個集合對象而不是一個數組。
#### 相關模型連接
相關模型現在將使用與父模型相同的連接。例如,你執行以下查詢:
~~~
User::on('example')->with('posts');
~~~
Eloquent 將查詢?`example`?連接上的 posts 表,而不是默認的數據庫連接。如果你想從默認連接讀取?`posts`?關系,你應該明確地設置模型的連接到你的應用程序的默認連接。
#### `create`?&?`forceCreate`?方法
`Model::create`?&?`Model:: forceCreate`?方法已經移動到?`Illuminate\Database\Eloquent\Builder`?類,以便為在多個連接上創建模型提供更好的支持。但是,如果要在自己的模型中擴展這些方法,則需要修改實現以在構建器上調用?`create`?方法。例如:
~~~
public static function create(array $attributes = [])
{
$model = static::query()->create($attributes);
// ...
return $model;
}
~~~
#### `hydrate`?方法
如果你現在傳遞自定義的連接名到該方法,需要使用?`on`?方法:
~~~
User::on('connection')->hydrate($records);
~~~
#### `hydrateRaw`?方法
`Model::hydrateRaw`?方法已經被重命名為?`fromQuery`?,如果你傳遞自定義的連接名到該方法,需要使用?`on`?方法:
~~~
User::on('connection')->fromQuery('...');
~~~
#### `whereKey`?方法
`whereKey($id)`?方法現在將為給定的主鍵值添加一個 「where」 子句。 在之前的版本中,這將屬于動態 「where」子句構建器,并為 「key」 列添加 「where」子句。如果你使用?`whereKey`?方法為?`key`?列動態添加一個條件,你現在應該使用?`where('key', ...)`?。
#### `factory`?Helper
調用?`factory(User::class, 1)->make()`?或?`factory(User::class, 1)->create()`?現在將返回一個集合。以前,這將返回單個模型。如果沒有傳入數量的話,返回的仍然只是單個模型。
### 事件
#### Contract 變更
如果你在應用程序或者包中手動實現?`Illuminate\Contracts\Events\Dispatcher`?接口,則應該將?`fire`?方法重命名為?`dispatch`。
#### 事件優先級
不再支持事件處理器 「優先級」 ,從未記錄的功能通常表示事件功能的濫用。相反,請考慮使用一系列同步方法調用。或者,你可以從另一個事件的處理程序中分派一個新事件,以確保給定事件的處理程序不在相關的處理程序之后觸發。
#### 通配符事件處理器簽名
通配符事件處理器現在接收事件名作為第一個參數以及事件數據作為第二個參數,?`Event::firing`?方法被移除:
~~~
Event::listen('*', function ($eventName, array $data) {
//
});
~~~
#### `kernel.handled`?事件
`kernel.handled`?事件現在是一個基于對象的事件,使用?`Illuminate\Foundation\Http\Events\RequestHandled`類。
#### `locale.changed`?事件
`locale.changed`?事件現在是一個基于對象的事件,使用?`Illuminate\Foundation\Events\LocaleUpdated`?類。
#### `illuminate.log`?事件
`illuminate.log`?事件現在是一個基于對象的事件,使用?`Illuminate\Log\Events\MessageLogged`?類。
### 異常
`Illuminate\Http\Exception\HttpResponseException`?已被重命名為`Illuminate\Http\Exceptions\HttpResponseException`?。注意?`Exceptions`?現在是復數。 類似的,`Illuminate\Http\Exception\PostTooLargeException`?已經被重命名為`Illuminate\Http\Exceptions\PostTooLargeException`。
### 郵件
#### `Class@method`?語法
不再支持使用?`Class@method`?語法發郵件。例如:
~~~
Mail::send('view.name', $data, 'Class@send');
~~~
如果你是以這種方式發送郵件,需要將這些調用做轉化?[mailables](https://laravel-china.org/docs/laravel/5.4/mail)?。
#### 新的配置選項
為了支持 Laravel 5.4 版本的 Markdown 郵件組件,你需要添加如下區域配置到?`mail`?配置文件底部:
~~~
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
~~~
#### 使用閉包將郵件推送到隊列
為了將郵件推送到隊列,必須使用?[mailable](https://laravel-china.org/docs/laravel/5.4/mail)?提供的方法。 使用?`Mail::queue`?和?`Mail::later`?方法將郵件推送到隊列,不再支持使用閉包來配置郵件消息。該功能需要使用指定的庫來序列化閉包,因為PHP原生不支持這一功能特性。
### Redis
#### 改進的集群支持
Laravel 5.4 引入了改進的 Redis 集群支持。 如果你正在使用 Redis 集群,則應該將集群連接置于?`config/database.php`?配置文件的 Redis 部分中的?`clusters`?配置選項內:
~~~
'redis' => [
'client' => 'predis',
'options' => [
'cluster' => 'redis',
],
'clusters' => [
'default' => [
[
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
],
],
~~~
### 路由
#### Post 大小中間件
`Illuminate\Foundation\Http\Middleware\VerifyPostSize`?類被重命名為`Illuminate\Foundation\Http\Middleware\ValidatePostSize`。
#### `middleware`?方法
`Illuminate\Routing\Router`?類的?`middleware`?方法已重命名為?`aliasMiddleware()`?。 似乎大多數應用都不會直接手動調用這個方法,因為這個方法只會被 HTTP kernel 調用,用于注冊定義在?`$routeMiddleware`?數組中的路由級中間件。
#### `Route`?方法
`Illuminate\Routing\Route`?類的?`getUri`?方法已刪除。你應該使用?`uri`?方法。
`Illuminate\Routing\Route`?類的?`getMethods`?方法已經刪除。你應該使用?`methods`?方法。
`Illuminate\Routing\Route`?類的?`getParameter`?方法已經刪除。你應該使用?`parameter`?方法。
`Illuminate\Routing\Route`?類的?`getPath`?方法已經刪除。你應該使用?`uri`?方法。
### 會話
#### Symfony兼容性
Laravel 的會話處理程序不再實現 Symfony 的?`SessionInterface`?。
實現這個接口需要我們實現框架不需要的無關特性。取而代之,已經定義了新的?`Illuminate\Contracts\Session\Session`?接口,并且可以使用。還應該修改一下代碼:
所有調用?`->set()`?方法應該更改為?`->put()`?。通常,Laravel 應用從不調用?`set`?方法,因為它從未在 Laravel 文檔中記錄。不過,謹慎起見,這里我們依然羅列出來。
所有調用?`->getToken()`?方法的地方需要修改為?`->token()`?。
所有調用?`$request->setSession()`?方法的地方需要求改為?`setLaravelSession()`?。
### 測試
Laravel 5.4 的測試層已經被重成更加簡單和更加輕量級。如果你想繼續使用 Laravel 5.3 中的測試層,你可以安裝?`laravel/browser-kit-testing`?[package](https://github.com/laravel/browser-kit-testing)?到你的應用程序。該包提供了與 Laravel 5.3 測試層的完全兼容。實際上,你可以同時運行 Laravel 5.3 和 Laravel 5.4 的測試層。
#### 在一個應用里面運行 Laravel 5.3 & 5.4 的測試
在開始之前,你應該將?`Tests`?命名空間添加到?`composer.json`?文件中的?`autoload-dev`?塊中。這將允許 Laravel 自動加載你使用 Laravel 5.4 測試生成器生成的任何新測試:
~~~
"psr-4": {
"Tests\\": "tests/"
}
~~~
接下來, 安裝?`laravel/browser-kit-testing`?包:
~~~
composer require laravel/browser-kit-testing
~~~
安裝軟件包后,創建?`tests/TestCase.php`?文件的副本,并將其作為?`BrowserKitTestCase.php`?保存到你的?`tests`?文件夾中。然后,修改該文件以擴展?`Laravel\BrowserKitTesting\TestCase`?類。完成之后,你應該在你的?`tests`?目錄中有兩個基本測試類:?`TestCase.php`?和?`BrowserKitTestCase.php`?。為了正確加載你的`BrowserKitTestCase`?類,你可能需要將它添加到你的?`composer.json`?文件:
~~~
"autoload-dev": {
"classmap": [
"tests/TestCase.php",
"tests/BrowserKitTestCase.php"
]
},
~~~
在 Laravel 5.3 上編寫的測試將擴展?`BrowserKitTestCase`?類,而使用 Laravel 5.4 測試層的任何新測試將擴展?`TestCase`?類。你的?`BrowserKitTestCase`?類應該如下所示:
~~~
<?php
use Illuminate\Contracts\Console\Kernel;
use Laravel\BrowserKitTesting\TestCase as BaseTestCase;
abstract class BrowserKitTestCase extends BaseTestCase
{
/**
* 應用的基礎 URL 。
*
* @var string
*/
public $baseUrl = 'http://localhost';
/**
* 創建應用。
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
~~~
創建好這些類之后,確保更新所有已編寫的測試類繼承自?`BrowserKitTestCase`?類,這將得所有基于 Laravel 5.3 編寫的測試類在 Laravel 5.4 中得以繼續運行。如果你選擇,你可以慢慢地開始將它們移植到新的?[Laravel 5.4 測試語法](https://laravel-china.org/docs/laravel/5.4/http-tests)?或者?[Laravel Dusk](https://laravel-china.org/docs/laravel/5.4/dusk)。
> {note} 如果你正在編寫新的測試,并且希望它們使用 Laravel 5.4 的測試層,確保繼承自?`TestCase`?類。
#### 在已升級應用中安裝 Duck
如果你想在已升級應用中安裝 Laravel Duck ,首先通過 Composer 安裝:
~~~
composer require laravel/dusk
~~~
記下來,你需要在?`tests`?目錄中創建一個?`CreatesApplication`?trait ,該 trait 用于為測試用例創建新的應用實例。該 trait 代碼如下:
~~~
<?php
use Illuminate\Contracts\Console\Kernel;
trait CreatesApplication
{
/**
* 創建應用。
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
~~~
> {note} 如果你的測試類位于某個命名空間下,并使用 PSR-4 自動加載標準來加載?`tests`?目錄,則應該將?`CreatesApplication`?trait 放置在合適的命名空間下。
完成了這些準備工作,你就可以按照正常的?[Dusk 安裝指南](https://laravel-china.org/docs/laravel/5.4/dusk#installation)?進行操作。
#### 環境
Laravel 5.4 不需要在每個測試類中手動強制設置?`putenv('APP_ENV=testing')`,取而代之,框架使用從?`.env`?文件中載入?`APP_ENV`?變量。
#### 時間偽造
`Event`?偽造的?`assertFired`?方法應該更新為?`assertDispatched`,并且?`assertNotFired`?方法應該更新為?`assertNotDispatched`?。方法的簽名沒有變更。
#### 郵件偽造
`Mail`?偽造在 Laravel 5.4 中極大的簡化。現在應該使用?`assertSent`?方法以及?`hasTo`,`hasCc`?等輔助函數即可即可,不再需要調用?`assertSentTo`?方法:
~~~
Mail::assertSent(MailableName::class, function ($mailable) {
return $mailable->hasTo('email@example.com');
});
~~~
### 翻譯
#### `{Inf}`?占位符
如果你在使用?`{Inf}`?占位符處理字符串復數格式的翻譯,你需要更新為使用?`*`?字符:
~~~
{0} First Message|{1,*} Second Message
~~~
### URL 生成
#### `forceSchema`?方法
`Illuminate\Routing\UrlGenerator`?類中的?`forceSchema`?方法已經重命名為?`forceScheme`。
### 驗證
#### 日期格式驗證
日期格式驗證現在更加嚴格,并支持對 PHP?[date function](http://php.net/manual/en/function.date.php)?中列出的占位符進行校驗。 在之前版本中,時區占位符?`P`?會接受所有的時區格式; 然而,在 Laravel 5.4 中,每種時區格式像在 PHP 文檔一樣,都有一個唯一的占位符。
#### 方法名
`addError`?方法已經重命名為?`addFailure`。此外,`doReplacements`?方法重命名為?`makeReplacements`。通常,這些改變只有當你去擴展?`Validator`?類時才會有影響。
### 雜項
我們同樣鼓勵你去翻閱?`laravel/laravel`?[GitHub 倉庫](https://github.com/laravel/laravel)?中的修改記錄。雖然很多修改不是必需的,你可能希望這些文件與你的應用程序同步。另外的一些變更將在本升級指南中介紹,但是其他更改不會。例如更改配置文件或者注釋。你可以通過?[Github comparison tool](https://github.com/laravel/laravel/compare/5.3...master)?很輕松的查看到這些變更,并選擇對你重要的更新。
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
| --- | --- | --- | --- |
| [@skyverd](https://laravel-china.org/users/79) | [](https://dn-phphub.qbox.me/uploads/avatars/79_1427370664.jpeg?imageView2/1/w/100/h/100) | 翻譯 | 全桟工程師,[時光博客](https://skyverd.com/) |
* * *
- 前言
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 請求周期
- 開發環境部署
- Homestead
- Valet
- 核心概念
- 服務容器
- 服務提供者
- Facades
- Contracts
- HTTP層
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- Session
- 表單驗證
- 前端
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 錯誤與日志
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Scout 全文搜索
- Socialite 社會化登錄