升级指南
从 5.3 升级到 5.4.0
预计升级时间:1-2 小时
我们尝试记录每一个可能的重大更改。由于这些重大更改中的一些位于框架的偏僻部分,只有一部分更改可能会实际影响您的应用程序。
更新依赖项
在您的 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 Passport 2.0.0
已发布,以提供与 Laravel 5.4 和 Axios JavaScript 库的兼容性。如果您从 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)
方法时,如果找不到策略,会抛出异常。现在,如果找不到给定类的策略,该方法将返回 null
。如果您直接调用此方法,请确保重构代码以检查 null
:
$policy = Gate::getPolicyFor($class);
if ($policy) {
// 以前在 try 块中的代码
} else {
// 以前在 catch 块中的代码
}
Blade
@section
转义
在 Laravel 5.4 中,传递给 section 的内联内容会自动转义:
@section('title', $content)
如果您希望在 section 中呈现未转义的内容,您必须使用传统的“长格式”样式声明 section:
@section('title')
{!! $content !!}
@stop
启动器
如果您手动覆盖 HTTP 或控制台内核上的 $bootstrappers
数组,您应该将 DetectEnvironment
条目重命名为 LoadEnvironmentVariables
并删除 ConfigureLogging
。
广播
通道模型绑定
在 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)
现在将返回一个包含一个项目的新集合实例。以前,这会返回一个单一对象。此方法仅在不提供参数时返回单一对象。
容器
通过 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
方法不再接受第二个参数数组。此功能通常表示代码味道。通常,您总是可以以更直观的方式构造对象。
如果必须继续传递参数数组,您可以使用 makeWith
方法。
解析回调
容器的 resolving
和 afterResolving
方法现在必须提供类名或绑定键作为方法的第一个参数:
$container->resolving('Class\Name', function ($instance) {
//
});
$container->afterResolving('Class\Name', function ($instance) {
//
});
share
方法已移除
share
方法已从容器中移除。这是一个遗留方法,已经有几年没有被记录。如果您正在使用此方法,您应该开始使用 singleton
方法:
$container->singleton('foo', function () {
return 'foo';
});
控制台
Illuminate\Console\AppNamespaceDetectorTrait
Trait
如果您直接引用 Illuminate\Console\AppNamespaceDetectorTrait
trait,请更新您的代码以引用 Illuminate\Console\DetectsApplicationNamespace
。
数据库
orWhere
的数组参数
当将数组作为第一个参数传递给 orWhere
方法时,内部条件现在在每个数组元素之间使用 OR
:
$query->orWhere(['a' => 1, 'b' => 2])
OR (a = 1 AND b = 2) // 以前的行为...
OR (a = 1 OR b = 2) // 新行为...
自定义连接
如果您以前为 db.connection.{driver-name}
键绑定服务容器绑定以解析自定义数据库连接实例,您现在应该在 AppServiceProvider
的 register
方法中使用 Illuminate\Database\Connection::resolverFor
方法:
use Illuminate\Database\Connection;
Connection::resolverFor('driver-name', function ($connection, $database, $prefix, $config) {
//
});
获取模式
Laravel 不再包括从配置文件中自定义 PDO “获取模式”的功能。相反,始终使用 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
模型的 $primaryKey
属性或 getKeyName
方法,行为可能与以前的版本不同。例如:
public function getKeyName()
{
return 'key';
}
在这种情况下,Laravel 现在将尊重您的自定义并确定外键列名为 user_key
而不是 user_id
。
BelongsToMany setJoin
setJoin
方法已重命名为 performJoin
。
BelongsToMany getRelatedIds
getRelatedIds
方法已重命名为 allRelatedIds
。
Has One / Many createMany
hasOne
或 hasMany
关系的 createMany
方法现在返回一个集合对象而不是数组。
Has One / Many getPlainForeignKey
getPlainForeignKey
方法已重命名为 getForeignKeyName
。
相关模型连接
相关模型现在将使用与父模型相同的连接。例如,如果您执行如下查询:
User::on('example')->with('posts');
Eloquent 将在 example
连接上查询 posts 表而不是默认数据库连接。如果您希望从默认连接读取 posts
关系,您应该显式将模型的连接设置为应用程序的默认连接。
chunk
方法
查询构建器 chunk
方法现在需要一个 orderBy
子句,这为 each
方法提供了一致性。如果未提供 orderBy
子句,将抛出异常。例如:
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
foreach ($users as $user) {
//
}
});
Eloquent 查询构建器 chunk
方法将在模型的主键上自动应用 orderBy
子句,如果未提供。
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
助手
调用 factory(User::class, 1)->make()
或 factory(User::class, 1)->create()
现在将返回一个包含一个项目的集合。以前,这会返回一个单一模型。此方法仅在未提供数量时返回单一模型。
newPivot
方法
Model::newPivot
方法签名已更新,添加了一个新的 $using
参数。新签名如下:
/**
* 创建一个新的 pivot 模型实例。
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param array $attributes
* @param string $table
* @param bool $exists
* @param string|null $using
* @return \Illuminate\Database\Eloquent\Relations\Pivot
*/
public function newPivot(Model $parent, array $attributes, $table, $exists, $using = null);
事件
合同更改
如果您在应用程序或包中手动实现 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。
新的配置选项
为了支持 Laravel 5.4 的新 Markdown 邮件组件,您应该在 mail
配置文件的底部添加以下配置块:
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
使用闭包队列邮件
为了队列邮件,您现在必须使用 mailable。使用 Mail::queue
和 Mail::later
方法队列邮件不再支持使用闭包配置邮件消息。此功能需要使用特殊库来序列化闭包,因为 PHP 本身不支持此功能。
队列
失败的作业表
如果您的应用程序包含 failed_jobs
表,您应该在表中添加一个 exception
列:
$table->longText('exception')->after('payload');
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 内核调用以注册在 $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
包 安装到您的应用程序中。此包提供与 Laravel 5.3 测试层的完全兼容性。实际上,您可以在同一应用程序中同时运行 Laravel 5.4 测试层和 Laravel 5.3 测试层。
为了允许 Laravel 自动加载您使用 Laravel 5.4 测试生成器生成的任何新测试,您应该将 Tests
命名空间添加到 composer.json
文件的 autoload-dev
块中:
"psr-4": {
"Tests\\": "tests/"
}
在单个应用程序中运行 Laravel 5.3 和 5.4 测试
首先安装 laravel/browser-kit-testing
包:
composer require --dev laravel/browser-kit-testing "1.*"
安装包后,创建 tests/TestCase.php
文件的副本,并将其保存到 tests
目录中为 BrowserKitTestCase.php
。然后,修改文件以扩展 Laravel\BrowserKitTesting\TestCase
类。完成此操作后,您应该在 tests
目录中有两个基本测试类:TestCase.php
和 BrowserKitTestCase.php
。为了正确加载 BrowserKitTestCase
类,您可能需要将其添加到 composer.json
文件中:
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
}
在 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 测试语法 或 Laravel Dusk。
如果您正在编写新测试并希望它们使用 Laravel 5.4 测试层,请确保扩展 TestCase
类。
在升级的应用程序中安装 Dusk
如果您希望在从 Laravel 5.3 升级的应用程序中安装 Laravel Dusk,首先通过 Composer 安装它:
composer require --dev laravel/dusk "1.*"
接下来,您需要在 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;
}
}
如果您已为测试命名空间并使用 PSR-4 自动加载标准加载 tests
目录,您应该将 CreatesApplication
trait 放在适当的命名空间下。
完成这些准备步骤后,您可以按照正常的 Dusk 安装说明 进行操作。
环境
Laravel 5.4 测试类不再手动为每个测试强制 putenv('APP_ENV=testing')
。相反,框架利用从加载的 .env
文件中的 APP_ENV
变量。
事件伪造
Event
伪造的 assertFired
方法应更新为 assertDispatched
,assertNotFired
方法应更新为 assertNotDispatched
。方法的签名没有更改。
邮件伪造
Mail
伪造在 Laravel 5.4 版本中大大简化。您不再使用 assertSentTo
方法,而是简单地使用 assertSent
方法,并在回调中使用 hasTo
、hasCc
等辅助方法:
Mail::assertSent(MailableName::class, function ($mailable) {
return $mailable->hasTo('email@example.com');
});
翻译
{Inf}
占位符
如果您正在使用 {Inf}
占位符来复数化您的翻译字符串,您应该更新您的翻译字符串以使用 *
字符:
{0} First Message|{1,*} Second Message
trans
助手
trans
助手签名已更新,删除了不必要的 $domain
参数。新签名如下:
/**
* 翻译给定的消息。
*
* @param string $id
* @param array $replace
* @param string $locale
* @return \Illuminate\Contracts\Translation\Translator|string|array|null
*/
function trans($id = null, $replace = [], $locale = null);
此外,trans_choice
助手已更新:
/**
* 根据计数翻译给定的消息。
*
* @param string $id
* @param int|array|\Countable $number
* @param array $replace
* @param string $locale
* @return string
*/
function trans_choice($id, $number, array $replace = [], $locale = null);
URL 生成
forceSchema
方法
Illuminate\Routing\UrlGenerator
类的 forceSchema
方法已重命名为 forceScheme
。
验证
日期格式验证
日期格式验证现在更加严格,并支持 PHP date 函数 文档中存在的占位符。在以前的 Laravel 版本中,时区占位符 P
会接受所有时区格式;然而,在 Laravel 5.4 中,每个时区格式都有一个独特的占位符,如 PHP 文档所示。
方法名称
addError
方法已重命名为 addFailure
。此外,doReplacements
方法已重命名为 makeReplacements
。通常,这些更改仅在您扩展 Validator
类时相关。
杂项
我们还鼓励您查看 laravel/laravel
GitHub 仓库 中的更改。虽然这些更改中的许多不是必需的,但您可能希望将这些文件与您的应用程序保持同步。这些更改中的一些将在本升级指南中介绍,但其他更改,例如配置文件或注释的更改,将不会被介绍。您可以使用 GitHub 比较工具 轻松查看更改,并选择哪些更新对您来说重要。