首页 » Laravel 5.3 中文文档 » 正文

「Laravel 5.3 中文文档」序言 – 升级指南

从 5.2.0 升级到 5.3.0

预计升级时间:2 – 3 小时

我们试图列出所有可能会受影响的地方,由于有些更新是在一些鲜有人用的地方,所以真正会影响你应用的地方并不会很多。

PHP & HHVM

Laravel 5.3 需要 PHP 5.6.4 或更高的版本,HHVM 将不再做官方支持,因为它与 PHP 5.6+ 并不是包含完全相同的特性。

数组

Key / Value 顺序做了更改

Arr 类的 first, last, contains 方法回调函数的第一个参数现在需要传 ‘value’。例如:

Arr::first(function ($value, $key) {
    return ! is_null($value);
});

在 Laravel 上一个版本中,$key 是第一个传递的。由于大多数使用情况中只会关心 $value ,所以现在它作为第一个参数。你需要在应用中对这三个方法做一个全局搜索,以核对 $value 是否是作为回调函数的第一个参数传递的。

Artisan

make:console 命令

make:console 重命名为了 make:command

用户认证

Authentication 脚手架

框架中默认提供的两个用户认证控制器分成了四个小的控制器。这个变更提供了更加简洁、清晰的用户认证控制器。把你的应用升级到新的用户认证的最简单的方式是从 Github 上获取最新的拷贝并放置到你的应用中。

你还需要确保在应用中的 routes.php 文件中调用 Route::auth() 方法,这个方法会为新的用户认证注册合适的路由。

当这些控制器放到你的应用中后,你需要重新实现你对这些控制器做的修改。例如,你修改过用户认证的 guard,那你可能需要重写控制器的 guard 方法,你可以检查每一个用户认证控制器的 trait 来决定覆盖哪些方法。

Note: 如果你没有对用户认证控制器做过修改的话,你只需要从 Github 获取最新的拷贝,并检查 routes.php 文件中是否有调用 Route::auth 方法。

密码重置邮件

密码重置邮件现在使用新的 Laravel 通知功能。当发送密码重置链接的时候,如果你想定制发送的通知,你可以覆盖 Illuminate\Auth\Passwords\CanResetPassword trait 的 sendPasswordResetNotification 方法。

你的 User 模型必须 use 新的 Illuminate\Notifications\Notifiable trait 以确保密码重置链接邮件可以成功发送。

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;
}
Note: 不要忘记在 config/app.php 配置文件的 providers 数组中注册 Illuminate\Notifications\NotificationServiceProvider

Logout 使用 POST 方法

Route::auth 方法会为 /logout 注册一个 POST 路由而非 GET 路由。这可以组织其他 WEB 应用能够登出你的应用的用户。升级的话,你或者更改你的登出请求使用 POST 方法,或者为 /logout URI 注册一个你自己的 GET 路由。

Route::get('/logout', 'Auth\LoginController@logout');

用户授权

使用 Class 名称调用 Policy 方法

一些 policy 方法只接受当前认证的用户,而非他们授权的模型的实例。最常见的是认证 create 方法。例如,当你发布一篇博客的时候,你可能希望检查这个用户是否具有发布博客的权限。

当定义不接受模型实例的 policy 方法的时候,例如 create 方法,类名将不再通过方法的第二个参数传递。你的方法只需要传递一个认证的用户实例。

/**
* Determine if the given user can create posts.
*
* @param \App\User $user
* @return bool
*/
public function create(User $user)
{
    //
}

AuthorizesResources trait

AuthorizesResources trait 现在已经与 AuthorizesRequests trait 合并,你需要删除 app/Http/Controllers/Controller.php 文件中的 AuthorizesResources trait。

Blade 模板

自定义指令

在 Laravel 上一个版本中,使用 directive 方法自定义 Blade 指令的时候,传递给回调函数的 $expression 必须包含在一个大括号内。

在 Laravel 5.3 中,包围在传递给回调函数的 $expression 外的大括号已经取消了。请查看 Blade 扩展 文档,并检查你定义的 Blade 指令是否还能正常使用。

// Laravel 5.2
Blade::directive('datetime', function($expression) {
return "<?php echo with{$expression}->format('m/d/Y H:i'); ?>";
});

// Laravel 5.3
Blade::directive('datetime', function($expression) {
return "<?php echo $expression->format('m/d/Y H:i'); ?>";
});

缓存

扩展闭包绑定了 $this

当使用闭包调用 Cache::extend 方法的时候,$this 会绑定到 CacheManager 实例,允许你在闭包中调用它的方法:

Cache::extend('memcached', function ($app, $config) {
    try {
        return $this->createMemcachedDriver($config);
    } catch (Exception $e) {
        return $this->createNullDriver($config);
    }
});

集合

Key / Value 顺序变更

first, last, contains 集合方法使用 value 作为回调函数的第一个参数,例如:

$collection->first(function ($value, $key) {
    return ! is_null($value);
});

在上一个版本的 Laravel 中,$key 是第一个参数。由于大多数使用情况中只关注 $value,它现在作为第一个参数传递。你需要在应用中对这三个方法做一个全局查找,检查 $value 是否是作为第一个参数传递的。

where 比较现在默认为宽松的

where 方法现在默认提供了一种宽松的比较而非严格比较,如果你要做一个严格比较的话,你可以使用 whereStrict 方法。

where 方法现在已经不再接受第三个参数来指定是否是“严格的”。你需要根据应用的需要明确指定调用 wherewhereStrict 方法。

数据库

集合

Query Builder 现在返回一个 Illuminate\Support\Collection 实例而非数组。这确保了 Query Builder 与 Eloquent 返回结果的一致性。

如果你不想把 Query Builder 查询结果合并为 Collection 实例,你可以在 Query Builder 的 get 方法后连接一个 all 方法。这将返回一个纯 PHP 的数组,允许你向后兼容维护。

$users = DB::table('users')->get()->all();

Eloquent $morphClass 属性

Eloquent 模型中可以定义的 $morphClass 属性已经被移除,被 “morph map” 取代。定义 morph map 可以为预加载提供支持,并解决了多态关系中额外的 BUG。如果你之前依赖 $morphClass 属性的话,可以使用下面的语法迁移到 morphMap :

Relation::morphMap([
    'YourCustomMorphName' => YourModel::class,
]);

例如,你之前定义了下面的 $morphClass 属性:

class User extends Model
{
    protected $morphClass = 'user'
}

你需要在 AppServiceProviderboot 方法中定义下面的 morphMap

use Illuminate\Database\Eloquent\Relation;

Relation::morphMap([
    'user' => User::class,
]);

Eloquent 的 save 方法

现在,当模型没有更改的话,save 方法将返回 false

Eloquent scopes

Eloquent scopes 现在优先考虑布尔值的 scope 约束。例如,当你的 scopeorWhere 约束开始的话,它将不再转换为 where 。如果你依赖这个功能(例如,在一个循环中添加多个 orWhere 条件),你需要核实第一个条件是普通的 where 以避免任何布尔逻辑问题。

如果你的 scopewhere 开始,则不需要进行任何修改。记得,你可以通过 toSql 方法来查看查询语句:

User::where('foo', 'bar')->toSql();

Join 闭包

JoinClause 类已经重写,以统一与 Query Builder 的语法。on 闭包函数中可选的 $where 参数已经取消。要添加 where 条件的话,你可以使用 Query Builder 提供的 where 方法:

$query->join('table', function($join) {
    $join->on('foo', 'bar')->where('bar', 'baz');
});

$bindings 属性也被移除了。想要使用 join 绑定的话,你可以直接使用 addBinding 方法:

$query->join(DB::raw('('.$subquery->toSql().') table'), function($join) use ($subquery) {
    $join->addBinding($subquery->getBindings(), 'join');
});

加密

Mcrypt encrypter 已经移除

2015 年 6 月发布 Laravel 5.1.0 的时候就已经弃用,在 5.3.0 中已经完全移除了,取而代之的是基于 OpenSSL 的新的算法实现,它自 Laravel 5.1.0 之后就一直作为默认的算法。

如果在 config/app.php 文件中你还在使用基于 cipher 的算法,你需要把它更改为 AES-256-CBC ,并把 key 设置为 32 位的随机字符串,可以通过 php artisan key:generate 来生成。

如果你已经在数据库中存储着 Mcrypt encrypter 的加密结果,你可以安装 laravel/legacy-encrypter ,它包含了遗留的 Mcrypt encrypter 实现。你应该使用这个包解密加密过的数据,并重新使用新的 OpenSSL 算法加密。例如你可以在自定义 Artisan 命令中像下面这样做:

$legacy = new McryptEncrypter($encryptionKey);

foreach ($records as $record) {
    $record->encrypted = encrypt(
        $legacy->decrypt($record->encrypted)
    );

    $record->save();
}

异常处理

构造函数

默认的异常处理现在需要给构造函数传递一个 Illuminate\Container\Container 实例。这个更改只会在你的应用的 app/Exception/Handler.php 文件中定义了 __construct 方法的时候受影响。如果你这么做了,你需要给 parent::__construct 方法传递一个 container 实例:

parent::__construct(app());

中间件

can 中间件的命名空间修改

在 HTTP kernel 中列出的 $routeMiddleware 属性中的 can 中间件需要更改为下面的类:

'can' => \Illuminate\Auth\Middleware\Authorize::class,

can 中间件认证异常

现在当用户未认证的时候,can 中间件会抛出一个 Illuminate\Auth\AuthenticationException 实例。你需要更改程序捕获该异常。多数情况下,这个更改不会影响你的应用程序。

绑定 Substitution 中间件

路由模型绑定现在支持使用中间件。所有应用现在都需要给 app/Http/Kernel.php 文件中的 web 中间件组添加 Illuminate\Routing\Middleware\SubstituteBindings 中间件。

\Illuminate\Routing\Middleware\SubstituteBindings::class,

并且需要在 HTTP kernel 的 $routeMiddleware 属性中注册该路由中间件:

'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,

路由中间件注册后,你需要把它添加到 api 中间件组中:

'api' => [
    'throttle:60,1',
    'bindings',
],

通知

安装

Laravel 5.3 提供了一个新的、基于驱动的通知系统。你需要在 config/app.php 文件的 providers 数组中注册 Illuminate\Notifications\NotificationServiceProvider 。并且需要在 alias 数组中添加 Illuminate\Support\Facades\Notification Facade。最后你可以在 User 模型或其他需要接收通知的模型中使用 Illuminate\Notifications\Notifiable trait。

分页

自定义

Laravel 5.3 与之前的 Laravel 5.x 版本相比,自定义分页生成的 HTML 更加容易了。你只需定义一个 Blade 模板即可,而不在需要定义 Presenter 类了。最简单的方法是通过 vendor:publish 命令把它们导出到 resources/views/vendor 目录:

php artisan vendor:publish --tag=laravel-pagination

这个命令会把视图放到 resources/views/vendor/pagination 文件夹中。文件夹中的 default.blade.php 对应的是默认的分页视图。只需编辑这个文件更改生成的分页 HTML。

请查看 分页 文档来获取更多内容。

队列

配置

在队列配置文件中,所有的 expire 配置项都要重命名为 retry_after 。同样的,Beanstalk 配置的 ttr 也需要重命名为 retry_after 。这个更改为配置项提供了更加清晰的目的。

闭包

队列闭包现在已经不再支持。如果你的应用使用闭包处理队列,你需要把闭包转换为一个类,并处理这个类的实例。

集合序列化

Illuminate\Queue\SerializesModels trait 现在可以正确的序列化 Illuminate\Database\Eloquent\Collection 的实例。对于大多数应用来说,这并不是一个破坏性的更改。但是如果你的应用依赖于不是通过 queued job 获取的数据集的 collections,那你应该核对下这个更改是否影响你的应用。

后台驻留任务

当调用 queue:work 命令时,不再需要指定 --daemon 选项了。运行 php artisan queue:work 命令会自动假定你想要在后台驻留程序中运行该任务。如果你想处理单一的任务,你需要使用该命令的 --once 选项:

// Start a daemon queue worker...
php artisan queue:work

// Process a single job...
php artisan queue:work --once

事件数据更改

各种队列任务事件如 JobProcessingJobProcessed 不再包含 $data 属性。你需要更新应用调用 $event->job->payload() 方法来获取相应的数据。

失败任务表

你的应用有个 failed_jobs 表,你需要为表添加一个 exception 列,exception 应该是 TEXT 类型的,用于存储导致任务失败的相应的字符串。

在遗留的队列任务中序列化模型

一般情况下,Laravel 的任务是通过给 Queue::push 传递一个任务实例实现队列化,然而,有些应用可能使用下面遗留的语法来序列化任务:

Queue::push('ClassName@method');

如果你使用这个语法来序列化任务,Eloquent 模型将不再自动序列化,并在队列中重新取回。如果你希望 Eloquent 模型在队列中自动序列化,你需要在任务类中使用 Illuminate\Queue\SerializesModels trait,并使用新的 push 语法队列化任务:

Queue::push(new ClassName);

路由

resource 参数将默认为单数

在上一个 Laravel 版本中,使用 Route::resource 注册的路由是非单数的。这在路由模型绑定中可能会导致一些意想不到的行为。例如,给定下面的 Route::resource 调用:

Route::resource('photos', 'PhotoController');

show 的 URI 将定义为下面这样:

/photos/{photos}

在 Laravel 5.3 中,所有的参数都将默认为单数。因此,相同的 Route::resource 调用将注册下面的 URI:

/photos/{photo}

如果你想维持之前的行为,而非把 resource 路由参数转为单数,你可以在 AppServiceProvider 中调用 singularResourceParameters 方法:

use Illuminate\Support\Facades\Route;

Route::singularResourceParameters(false);

resource 路由名称将不再受前缀影响

当使用 Route::resource 时,URL 前缀将不再影响分配的路由名称,因为这个行为会导致希望使用路由名称为第一位的目的失败。

如果你的应用在指定了 prefixRoute::group 中调用 Route::resource,你需要检查所有调用 route 辅助方法的地方,确保已经不再在路由名称前添加 prefix URI。

如果这个更改导致你有两个路由使用相同的名称,当调用 Route::resource 的时候你可以使用 names 选项来给一个指定的路由定义名称。参考 resource 路由 获取更多内容。

验证

Form Request 异常

如果表的请求验证失败,Laravel 现在回抛出一个 Illuminate\Validation\ValidationException 实例而非 HttpException 实例。如果你手动捕获有表单请求抛出的 HttpException 实例,你需要更新 catch 代码块来捕获 ValidationException 异常。

原始的 Nullable

当验证数组、布尔、整型、数字、以及字符串的时候, null 将不再作为一个正确的值,除非指定了新的 nullable 规则:

Validate::make($request->all(), [
    'string' => 'nullable|max:5',
]);

该篇属于专题:《Laravel 5.3 中文文档

本文共 2 个回复

  • php 2016/08/21 17:44

    赞,laravel又升级了,要求php5.6+,可惜现在还在用5.0.。。。

    • Specs 2016/08/21 19:15

      @ php 都这个年代了,还用 5.0 啊。。人家很多都在用 7.0 了~

发表评论