Skip to content

升级指南

从 5.3 升级到 5.4.0

预计升级时间:1-2 小时

exclamation

我们尝试记录每一个可能的重大更改。由于这些重大更改中的一些位于框架的偏僻部分,只有一部分更改可能会实际影响您的应用程序。

更新依赖项

在您的 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 包:

php
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

php
$policy = Gate::getPolicyFor($class);

if ($policy) {
    // 以前在 try 块中的代码
} else {
    // 以前在 catch 块中的代码
}

Blade

@section 转义

在 Laravel 5.4 中,传递给 section 的内联内容会自动转义:

php
@section('title', $content)

如果您希望在 section 中呈现未转义的内容,您必须使用传统的“长格式”样式声明 section:

php
@section('title')
    {!! $content !!}
@stop

启动器

如果您手动覆盖 HTTP 或控制台内核上的 $bootstrappers 数组,您应该将 DetectEnvironment 条目重命名为 LoadEnvironmentVariables 并删除 ConfigureLogging

广播

通道模型绑定

在 Laravel 5.3 中定义通道名称占位符时,使用 * 字符。在 Laravel 5.4 中,您应该使用 {foo} 样式占位符定义这些占位符,如路由:

php
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 版本中,您可以将数组作为第一个参数传递给 bindinstance 方法来注册别名:

php
$container->bind(['foo' => FooContract::class], function () {
    return 'foo';
});

然而,这种行为在 Laravel 5.4 中已被移除。要注册别名,您现在应该使用 alias 方法:

php
$container->alias(FooContract::class, 'foo');

带前导斜杠的绑定类

不再支持将带前导斜杠的类绑定到容器中。此功能需要在容器内进行大量字符串格式化调用。相反,只需在没有前导斜杠的情况下注册您的绑定:

php
$container->bind('Class\Name', function () {
    //
});

$container->bind(ClassName::class, function () {
    //
});

make 方法参数

容器的 make 方法不再接受第二个参数数组。此功能通常表示代码味道。通常,您总是可以以更直观的方式构造对象。

如果必须继续传递参数数组,您可以使用 makeWith 方法。

解析回调

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

php
$container->resolving('Class\Name', function ($instance) {
    //
});

$container->afterResolving('Class\Name', function ($instance) {
    //
});

share 方法已移除

share 方法已从容器中移除。这是一个遗留方法,已经有几年没有被记录。如果您正在使用此方法,您应该开始使用 singleton 方法:

php
$container->singleton('foo', function () {
    return 'foo';
});

控制台

Illuminate\Console\AppNamespaceDetectorTrait Trait

如果您直接引用 Illuminate\Console\AppNamespaceDetectorTrait trait,请更新您的代码以引用 Illuminate\Console\DetectsApplicationNamespace

数据库

orWhere 的数组参数

当将数组作为第一个参数传递给 orWhere 方法时,内部条件现在在每个数组元素之间使用 OR

php
$query->orWhere(['a' => 1, 'b' => 2])

OR (a = 1 AND b = 2) // 以前的行为...

OR (a = 1 OR b = 2) // 新行为...

自定义连接

如果您以前为 db.connection.{driver-name} 键绑定服务容器绑定以解析自定义数据库连接实例,您现在应该在 AppServiceProviderregister 方法中使用 Illuminate\Database\Connection::resolverFor 方法:

php
use Illuminate\Database\Connection;

Connection::resolverFor('driver-name', function ($connection, $database, $prefix, $config) {
    //
});

获取模式

Laravel 不再包括从配置文件中自定义 PDO “获取模式”的功能。相反,始终使用 PDO::FETCH_OBJ。如果您仍然希望为您的应用程序自定义获取模式,您可以监听新的 Illuminate\Database\Events\StatementPrepared 事件:

php
Event::listen(StatementPrepared::class, function ($event) {
    $event->statement->setFetchMode(...);
});

Eloquent

日期转换

date 转换现在将列转换为 Carbon 对象并调用对象上的 startOfDay 方法。如果您希望保留日期的时间部分,您应该使用 datetime 转换。

外键约定

如果在定义关系时未显式指定外键,Eloquent 现在将使用相关模型的表名和主键名来构建外键。对于绝大多数应用程序,这不是行为的变化。例如:

php
public function user()
{
    return $this->belongsTo(User::class);
}

就像以前的 Laravel 版本一样,这种关系通常会使用 user_id 作为外键。然而,如果您覆盖了 User 模型的 $primaryKey 属性或 getKeyName 方法,行为可能与以前的版本不同。例如:

php
public function getKeyName()
{
    return 'key';
}

在这种情况下,Laravel 现在将尊重您的自定义并确定外键列名为 user_key 而不是 user_id

BelongsToMany setJoin

setJoin 方法已重命名为 performJoin

BelongsToMany getRelatedIds

getRelatedIds 方法已重命名为 allRelatedIds

Has One / Many createMany

hasOnehasMany 关系的 createMany 方法现在返回一个集合对象而不是数组。

Has One / Many getPlainForeignKey

getPlainForeignKey 方法已重命名为 getForeignKeyName

相关模型连接

相关模型现在将使用与父模型相同的连接。例如,如果您执行如下查询:

php
User::on('example')->with('posts');

Eloquent 将在 example 连接上查询 posts 表而不是默认数据库连接。如果您希望从默认连接读取 posts 关系,您应该显式将模型的连接设置为应用程序的默认连接。

chunk 方法

查询构建器 chunk 方法现在需要一个 orderBy 子句,这为 each 方法提供了一致性。如果未提供 orderBy 子句,将抛出异常。例如:

php
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
    foreach ($users as $user) {
        //
    }
});

Eloquent 查询构建器 chunk 方法将在模型的主键上自动应用 orderBy 子句,如果未提供。

createforceCreate 方法

Model::createModel::forceCreate 方法已移至 Illuminate\Database\Eloquent\Builder 类,以便更好地支持在多个连接上创建模型。然而,如果您在自己的模型中扩展这些方法,您将需要修改您的实现以在构建器上调用 create 方法。例如:

php
public static function create(array $attributes = [])
{
    $model = static::query()->create($attributes);

    // ...

    return $model;
}

hydrate 方法

如果您当前正在将自定义连接名称传递给此方法,您现在应该使用 on 方法:

php
User::on('connection')->hydrate($records);

hydrateRaw 方法

Model::hydrateRaw 方法已重命名为 fromQuery。如果您将自定义连接名称传递给此方法,您现在应该使用 on 方法:

php
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 参数。新签名如下:

php
/**
 * 创建一个新的 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 方法已被移除:

php
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 语法发送邮件。例如:

php
Mail::send('view.name', $data, 'Class@send');

如果您以这种方式发送邮件,您应该将这些调用转换为 mailables

新的配置选项

为了支持 Laravel 5.4 的新 Markdown 邮件组件,您应该在 mail 配置文件的底部添加以下配置块:

php
'markdown' => [
    'theme' => 'default',

    'paths' => [
        resource_path('views/vendor/mail'),
    ],
],

使用闭包队列邮件

为了队列邮件,您现在必须使用 mailable。使用 Mail::queueMail::later 方法队列邮件不再支持使用闭包配置邮件消息。此功能需要使用特殊库来序列化闭包,因为 PHP 本身不支持此功能。

队列

失败的作业表

如果您的应用程序包含 failed_jobs 表,您应该在表中添加一个 exception 列:

php
$table->longText('exception')->after('payload');

Redis

改进的集群支持

Laravel 5.4 引入了改进的 Redis 集群支持。如果您正在使用 Redis 集群,您应该将集群连接放在 config/database.php 配置文件的 Redis 部分的 clusters 配置选项中:

php
'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 块中:

php
"psr-4": {
    "Tests\\": "tests/"
}

在单个应用程序中运行 Laravel 5.3 和 5.4 测试

首先安装 laravel/browser-kit-testing 包:

php
composer require --dev laravel/browser-kit-testing "1.*"

安装包后,创建 tests/TestCase.php 文件的副本,并将其保存到 tests 目录中为 BrowserKitTestCase.php。然后,修改文件以扩展 Laravel\BrowserKitTesting\TestCase 类。完成此操作后,您应该在 tests 目录中有两个基本测试类:TestCase.phpBrowserKitTestCase.php。为了正确加载 BrowserKitTestCase 类,您可能需要将其添加到 composer.json 文件中:

php
"autoload-dev": {
    "psr-4": {
        "Tests\\": "tests/"
   }
}

在 Laravel 5.3 上编写的测试将扩展 BrowserKitTestCase 类,而使用 Laravel 5.4 测试层的任何新测试将扩展 TestCase 类。您的 BrowserKitTestCase 类应如下所示:

php
<?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

exclamation

如果您正在编写新测试并希望它们使用 Laravel 5.4 测试层,请确保扩展 TestCase 类。

在升级的应用程序中安装 Dusk

如果您希望在从 Laravel 5.3 升级的应用程序中安装 Laravel Dusk,首先通过 Composer 安装它:

php
composer require --dev laravel/dusk "1.*"

接下来,您需要在 tests 目录中创建一个 CreatesApplication trait。此 trait 负责为测试用例创建新的应用程序实例。trait 应如下所示:

php
<?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;
    }
}
exclamation

如果您已为测试命名空间并使用 PSR-4 自动加载标准加载 tests 目录,您应该将 CreatesApplication trait 放在适当的命名空间下。

完成这些准备步骤后,您可以按照正常的 Dusk 安装说明 进行操作。

环境

Laravel 5.4 测试类不再手动为每个测试强制 putenv('APP_ENV=testing')。相反,框架利用从加载的 .env 文件中的 APP_ENV 变量。

事件伪造

Event 伪造的 assertFired 方法应更新为 assertDispatchedassertNotFired 方法应更新为 assertNotDispatched。方法的签名没有更改。

邮件伪造

Mail 伪造在 Laravel 5.4 版本中大大简化。您不再使用 assertSentTo 方法,而是简单地使用 assertSent 方法,并在回调中使用 hasTohasCc 等辅助方法:

php
Mail::assertSent(MailableName::class, function ($mailable) {
    return $mailable->hasTo('email@example.com');
});

翻译

{Inf} 占位符

如果您正在使用 {Inf} 占位符来复数化您的翻译字符串,您应该更新您的翻译字符串以使用 * 字符:

php
{0} First Message|{1,*} Second Message

trans 助手

trans 助手签名已更新,删除了不必要的 $domain 参数。新签名如下:

php
/**
 * 翻译给定的消息。
 *
 * @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 助手已更新:

php
/**
 * 根据计数翻译给定的消息。
 *
 * @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 比较工具 轻松查看更改,并选择哪些更新对您来说重要。