[ Laravel 5.4 文档 ] 序言 —— 升级指南

文档适用于从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.phpproviders数组中注册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方法不再接收第二个数组参数,因为该特性表明了代码的坏味道。我们需要以更加直观的方式来构造对象。

解析回调

容器的resolvingafterResolving方法现在必须传入一个类名或绑定键作为第一个参数:

$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}绑定了一个服务容器绑定以便解析自定义数据库连接实例,现在需要在AppServiceProviderregister方法中使用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

hasOnehasMany关联关系的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::queueMail::later方法将邮件推送到队列不再支持使用闭包配置邮件消息,该功能需要使用指定的库类序列化闭包,因为PHP原生代码不再支持这一功能特性。

Redis

优化Cluster支持

Laravel 5.4对Redis Cluster支持进行优化,如果你在使用Redis Cluster,需要将Cluster连接信息放置在Redis配置文件config/database.phpclusters配置项中:

'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

兼容Symfony

Laravel的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.phpBrowserKitTest.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自动载入标准加载tests目录下的类,则需要将CreatesApplication放置在命名空间下。

完成上述准备工作之后,就可以按照正常的Dusk安装指南继续执行下去了。

环境

Laravel 5.4不再需要在每个测试类中手动强制设置putenv('APP_ENV=testing'),取而代之,框架使用从.env文件中载入的APP_ENV变量。

事件伪造

Event伪造的assertFired方法需要修改为assertDispatched,方法参数则不需要修改。

邮件伪造

Mail伪造在Laravel 5.4中进行了极大的简化,只需在回调中使用assertSent方法以及hasTohasCc等辅助函数即可,不再需要调用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/laravelGitHub仓库的修改记录。有些修改在这篇文档中已经提及,但是另外一些比如对配置文件的修改,或者注释的调整,这里并没有覆盖到,你可以借助Github comparison tool轻松查看更改,并重点关注下你所感兴趣的修改。

学院君 has written 682 articles

资深PHP工程师,Laravel学院院长

3 thoughts on “[ Laravel 5.4 文档 ] 序言 —— 升级指南

发表评论

标记为*的字段是必填项(邮箱地址不会被公开)

你可以使用这些HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>