升级指南
本文档适用于从Laravel 5.3升级到5.4.0,预计升级时间:1-2小时。
升级依赖
将composer.json
文件中的laravel/framework
依赖升级到5.4.*
。此外,还需要更新phpunit/phpunit
依赖的版本为~5.7
。
清空缓存
升级完所有包之后,需要运行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 JavaScript 库,Laravel Passport已经发布2.0.0
版本,如果你是从Laravel 5.3升级并且使用了预置的Passport Vue组件,需要确保Axios库以axios
的形式在应用全局有效。
Laravel Scout
为了兼容Laravel 5.4,Laravel Scout已经发布3.0.0
版本。
Laravel Socialite
为了兼容Laravel 5.4,Laravel Socialite已经发布3.0.0
版本。
Laravel Tinker
为了可以在Artisan命令中继续使用tinker
命令,需要安装laravel/tinker
扩展包:
composer require laravel/tinker
安装完成后,需要在config/app.php
的providers
数组中注册Laravel\Tinker\TinkerServiceProvider::class
。
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('title')
{!! $content !!}
@stop
Bootstrappers
如果你在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的新的集合实例。在之前版本中,这个方法会返回单个对象。如果没有提供参数,该方法将只返回单个对象。
容器
通过\绑定类
通过带有\的类名绑定类到容器将不再被支持,因为该功能需要在底层容器中进行大量的字符串格式化调用。取而代之地,只需通过下面这种不带\的方式绑定即可:
$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';
});
控制台
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
,如果你仍然想要为应用定制fetch模式,需要监听新的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
或hasMany
关联关系的createMany
方法现在会返回一个集合对象而不是数组。
关联模型连接
关联模型现在使用和父级模型一样的连接,例如,如果你执行的是这样的查询:
User::on('example')->with('posts');
Eloquent会在example
连接上查询posts表,而不是默认的数据库连接。如果你想要从默认的数据库连接上读取posts
关联关系,需要显式设置模型的连接为应用的默认连接。
hydrate方法
如果你现在传递自定义的连接名到该方法,需要使用on
方法:
User::on('connection')->hydrate($records);
hydrateRaw方法
Model::hydrateRaw
方法已经被重命名为fromQuery
,如果你传递自定义的连接名到该方法,需要使用on
方法:
User::on('connection')->fromQuery('...');
whereKey方法
whereKey($id)
方法现在会为给定主键值添加一个where子句,在之前的版本中,该方法会调用魔术函数动态构建where子句,最终的结果是where key = $id
。现在,如果你想要实现同样的功能,需要使用where('key', ...)
方式来取代。
辅助函数factory
调用factory(User::class, 1)->make()
或factory(User::class, 1)->create()
现在会返回包含单个item的集合,在之前的版本中,返回的则是单个模型。如果没有传入数量的话,返回的仍然只是单个模型。
事件
契约修改
如果你在应用或扩展包中手动实现了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');
如果你是以这种方式发送邮件,需要将这些调用做转化(详情请参考邮件文档)。
新的配置选项
为了支持Laravel 5.4版本的Markdown邮件组件,需要添加如下配置区块到mail
配置文件底部:
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
使用闭包将邮件推送到队列
为了将邮件推送到队列,必须使用邮件文档中提供的方法。使用Mail::queue
或Mail::later
方法将邮件推送到队列不再支持使用闭包配置邮件消息,该功能需要使用指定的库类序列化闭包,因为PHP原生代码不再支持这一功能特性。
Redis
优化Cluster支持
Laravel 5.4对Redis Cluster支持进行优化,如果你在使用Redis Cluster,需要将Cluster连接信息放置在Redis配置文件config/database.php
的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
数组中的路由级别的中间件。
getParameter方法
Illuminate\Routing\Route
类的getParameter
已经被移除。需要使用parameter
方法来替代。
Session
兼容SymfonyLaravel的session处理器不再实现Symfony的SessionInterface
,实现这个接口需要我们实现框架不需要的额外功能特性,所以,取而代之,我们定义了一个新的Illuminate\Contracts\Session\Session
接口。下面这些代码的更改也将被应用:
所有调用->set()
方法的地方都需要修改为->put()
。通常,Laravel应用永远不会调用set方法,不过,谨慎起见,这里我们依然罗列出来。
所有调用->getToken()
方法的地方需要修改为->token()
。
所有调用$request->setSession()
方法的地方需要修改为setLaravelSession()
。
测试
Laravel 5.4的测试层已经被重写以便更加简单,更加轻量级。如果你想继续使用Laravel 5.3的测试层,需要在应用中安装laravel/browser-kit-testing
扩展包。该扩展包完全兼容Laravel 5.3测试层。实际上,你可以同时使用Laravel 5.4和5.3的测试功能。
如果你的测试类都是通过Laravel 5.3编写,并且想要同时使用新版本的测试层,则需要安装laravel/browser-kit-testing
扩展包:
composer require laravel/browser-kit-testing
接下来,拷贝tests/TestCase.php
文件到tests
目录下并将其重命名为BrowserKitTest.php
,然后,编辑该文件继承自Laravel\BrowserKitTesting\TestCase
类。完成之后,你在tests
目录下就有了两个测试基类:TestCase.php
和BrowserKitTest.php
。为了让BrowserKitTest
类可以正常加载,需要将其添加到composer.json
文件:
"autoload-dev": {
"classmap": [
"tests/TestCase.php",
"tests/BrowserKitTest.php"
]
},
基于Laravel 5.3编写的测试类继承自BrowserKitTest
,而所有基于Laravel 5.4编写的测试类继承自TestCase
类。BrowserKitTest
类代码如下:
<?php
use Illuminate\Contracts\Console\Kernel;
use Laravel\BrowserKitTesting\TestCase as BaseTestCase;
abstract class BrowserKitTest extends BaseTestCase
{
/**
* The base URL of the application.
*
* @var string
*/
public $baseUrl = 'http://localhost';
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
创建好这些类之后,确保更新所有已编写测试类继承自BrowserKitTest
类,这将使得所有基于Laravel 5.3编写的测试类在Laravel 5.4中得以继续运行。
如果是编写新的基于Laravel 5.4的测试类,确保继承自TestCase
类。
在已升级应用中安装Dusk
如果你想要在已升级应用中安装Laravel Dusk,首先通过Composer安装:
composer require laravel/dusk
接下来,需要在tests
目录下创建一个CreatesApplication
trait,该trait用于为测试用例创建新的应用实例。该trait代码如下:
<?php
use Illuminate\Contracts\Console\Kernel;
trait CreatesApplication
{
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
如果你的测试类位于某个命名空间下,并且使用了PSR-4自动载入标准加载完成上述准备工作之后,就可以按照正常的Dusk安装指南继续执行下去了。tests
目录下的类,则需要将CreatesApplication
放置在命名空间下。
环境
Laravel 5.4不再需要在每个测试类中手动强制设置putenv('APP_ENV=testing')
,取而代之,框架使用从.env
文件中载入的APP_ENV
变量。
事件伪造
Event
伪造的assertFired
方法需要修改为assertDispatched
,方法参数则不需要修改。
邮件伪造
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日期函数文档中列出的占位符进行校验。在之前版本中,时区占位符P
会接收所有的时区格式,在Laravel 5.4中,每种时区格式都有一个唯一的占位符。
方法名
addError
方法已经被重命名为addFailure
,此外,doReplacements
方法已经被重命名为makeReplacements
。通常,这些改变只有当你去扩展Validator
类时才会有影响。
杂项
我们还鼓励你去翻阅laravel/laravel
GitHub仓库的修改记录。有些修改在这篇文档中已经提及,但是另外一些比如对配置文件的修改,或者注释的调整,这里并没有覆盖到,你可以借助Github comparison tool轻松查看更改,并重点关注下你所感兴趣的修改。
3 Comments