升级指南
从 5.2 升级到 5.3
注:预计升级升级时间:2-3小时
PHP & HHVM
Laravel 5.3要求PHP 5.6.4及以上版本,官方将不再支持HHVM,因为其不包含PHP 5.6+新提供的语言特性。
废弃
所有罗列在Laravel 5.2升级指南中的废弃功能都已从框架中移除,你需要查看这个列表以确定不再使用这些废弃功能。
数组
key/value顺序更改
Arr
类上的first
、last
、以及contains
方法现在将“value”作为第一个参数传递给给定闭包,例如:
Arr::first(function ($value, $key) { return ! is_null($value); });
在Laravel之前版本中,$key
是第一个参数,但是由于大多数使用案例只对$value
感兴趣,所以我们将其放到第一个。你可以在应用中进行一次全局搜索以验证是否你在应用中通过旧的方式使用了这个函数。
Artisan
make:console命令
make:console
命令现在被重命名为make:command
。
认证
认证脚手架
Laravel框架提供的默认的两个认证控制器已经被分割成四个,这一更改让认证控制器变得更加清爽、责任更加明确。升级应用认证控制器到最新的最简单方法就是从GitHub上将四个控制器代码拷贝过来复制到项目中。
你还要确保在路由文件中调用了Route::auth()
方法,该方法在底层已经为新控制器注册了合适的路由。
这些新控制器拷贝到应用后,需要重新实现之前在认证控制器中实现的方法和业务。例如,如果你在自定义用于认证的guard,需要重写控制器的guard
方法,你可以检查每个认证控制器的trait以判断要重写哪些方法。
注:如果你没有自定义认证控制器,只需要将代码从Github拷到本地项目,并确保在路由文件中调用了Route::auth
方法。
密码重置邮件
密码重置邮件现在使用新的通知功能(Laravel Notifications),如果你想要在发送密码重置链接的时候自定义通知发送,需要重写Illuminate\Auth\Passwords\CanResetPassword
trait上的sendPasswordResetNotification
方法。
User
模型必须使用新的Illuminate\Notifications\Notifiable
trait以便邮件重置链接可以正常发送:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
}
注:不要忘了在配置文件config/app.php
的providers
数组中注册服务提供者Illuminate\Notifications\NotificationServiceProvider
。
POST到Logout
Route::auth
方法现在为/logout
注册了一个POST路由取代之前的GET路由。这可以防止其它应用让用户从应用中退出。想要升级的话,需要将原来的退出请求转化为POST请求方式,或者为/logout
URI自定义GET路由:
Route::get('/logout', 'Auth\LoginController@logout');
授权
使用类名调用策略方法
有时候一些策略方法只接收当前认证用户而不是授权模型实例,最常见的场景就是授权create
动作。例如,如果你在创建一篇博客,你可能希望检查当前用户是否被授权创建文章。
当定义一个不接收模型实例的策略方法时,比如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中,这些最外层的括号将不再包含在传递给指令回调的表达式中,请查看Blade文档确保自定义的Blade指令还能正常工作。
广播
服务提供者
Laravel 5.3 对事件广播进行了显著的优化,需要添加的新的BroadcastServiceProvider
(从GitHub下载文件)到app/Providers
目录,然后将这个新的服务提供者注册到配置文件config/app.php
的providers
数组中。
缓存
扩展闭包绑定&$this
使用闭包调用Cache::extend
方法时,$this
会被绑定到CacheManager
实例,从而允许你在扩展闭包中调用其提供的方法:
Cache::extend('memcached', function ($app, $config) { try { return $this->createMemcachedDriver($config); } catch (Exception $e) { return $this->createNullDriver($config); } });
Cashier
如果你在使用Cashier,需要升级laravel/cashier
扩展包到7.0版本,这一版本的Cashier只修改了一些内置方法以便兼容于Laravel 5.3,并没有什么重大更新。
集合
key/value顺序调整
集合方法first
, last
和contains
都将“value”作为第一个参数传递给相应的回调闭包,例如:
$collection->first(function ($value, $key) { return ! is_null($value); });
在Laravel之前的版本中,$key
是第一个参数,由于大部分使用案例只对$value
感兴趣,所以将其调整为第一个,你需要在应用中对这些方法做一个全局搜索,以验证$value
是否按照期望的方式以第一个参数传入闭包。
where默认使用非严格比较
where
现在默认使用非严格比较而不是之前的严格比较,如果你想要进行严格比较,可以使用whereStrict
方法。
where
方法也不再接收第三个参数标识“严格”,你需要基于应用的需求区分调用where
或whereStrict
。
控制器
构造函数当中使用Session
在Laravel以前的版本中,你可以在控制器构造函数中获取session变量或者认证后的用户实例。框架从未打算具有如此明显的特性。在Laravel 5.3中,你在控制器构造函数中不再能够直接获取到session变量或认证后的用户实例,因为中间件还未启动。
仍然有替代方案,那就是在控制器构造函数中使用Closure来直接定义中间件。请注意,在使用这个方案的时候,确保你所使用的Laravel版本高于 5.3.4
:
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class ProjectController extends Controller
{
/**
* 当前用户的的所有Projects.
*/
protected $projects;
/**
* 创建新的控制器实例.
*
* @return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
当然,你可以在控制器的其他方法中依靠Illuminate\Http\Request
类获取到session以及认证用户信息。
/** * 获取当前用户的所有Projects. * * @param \Illuminate\Http\Request $request * @return Response */ public function index(Request $request) { $projects = $request->user()->projects; $value = $request->session()->get('key'); // }
声明:控制器session部分由网友AC1982(微信号)提供翻译支持。
数据库
集合
查询构建器现在返回Illuminate\Support\Collection
实例而不是原生数组,以便保持和Eloquent返回结果类型一致。
如果你不想要迁移查询构建器结果到Collection实例,可以在查询构建器的get
方法后调用call
方法,这将会返回原生的PHP数组结果,从而保证向后兼容:
$users = DB::table('users')->get()->all();
Eloquent $morphClass 属性
可以在Eloquent模型上定义的$morphClass
属性已经被移除,以便定义一个“morph map”(变形映射),定义变形映射可以支持渴求式加载并且解决使用多态关联关系引起的额外bugs,如果你之前使用了$morphClass
属性,需要使用如下语法将其迁移到morphMap
:
Relation::morphMap([ 'YourCustomMorphName' => YourModel::class, ]);
例如,如果你之前定义了如下$morphClass
:
class User extends Model { protected $morphClass = 'user' }
现在则需要在AppServiceProvider
的boot
方法中定义如下morphMap
:
use Illuminate\Database\Eloquent\Relations\Relation; Relation::morphMap([ 'user' => User::class, ]);
Eloquent save方法
如果模型在上一次获取或保存之后被改变过,调用Eloquent的save
方法会返回false
。
Eloquent 作用域
Eloquent作用域现在会以第一个作用域约束的布尔值为准,例如,如果你的作用域以orWhere
开头,则将不再被转化为正常的where
。如果你现在的代码中使用了这个特性(在循环中添加了多个orWhere
约束),需要验证第一个条件是否是正常的where
以避免布尔逻辑问题。
如果你的作用域约束都是以where
开头则不需要做任何调整,你可以通过toSql
方法查看当前的SQL语句:
User::where('foo', 'bar')->toSql();
join 语句
JoinClause
类被重写以便统一查询构建器的语法,on
方法上可选的$where
参数已被移除,要添加where
条件需要显式使用查询构建器提供的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加密被移除
Laravel 5.1.0版本中Mcrypt加密就已经被废弃,在Laravel 5.3中该功能被完全移除,以便于统一使用基于OpenSSL的新的加密实现,该实现从Laravel 5.1.0开始就已经作为默认的加密实现方式。
如果你还在配置文件config/app.php
中使用基于cipher
的Mcrypt加密,需要将cipher
更新到AES-256-CBC
并且将key设置为32位随机字符串(这可以通过Artisan命令php artisan key:generate
生成)。
如果你在使用Mcrypt加密保存加密数据到数据库,则需要安装包含Mcrypt加密实现的扩展包laravel/legacy-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
方法:
parent::__construct(app());
中间件
can中间件命名空间修改
罗列在HTTP Kernel的$routeMiddleware
属性中的can
中间件需要作如下修改:
'can' => \Illuminate\Auth\Middleware\Authorize::class,
can中间件认证异常
如果用户没有认证的话can
中间件会抛出Illuminate\Auth\AuthenticationException
异常实例,如果你手动捕获了其它异常类型,需要修改为捕获这个异常,在大多数案例中,这一修改对应用不会造成影响。
绑定替代中间件
路由模型绑定现在通过中间件来完成,所有应用都需要在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', ],
通知(Notifications)
安装
Laravel 5.3内置了一个新的、基于驱动的通知系统,你需要在配置文件config/app.php
的providers
数组中注册服务提供者Illuminate\Notifications\NotificationServiceProvider
。
你还需要在配置文件config/app.php
的aliases
数组中注册门面Illuminate\Support\Facades\Notification
。
最后,你可以在User
模型或其它你希望接收通知的模型中使用 Illuminate\Notifications\Notifiable
trait。
分页
自定义
与之前版本的Laravel相比,Laravel 5.3中自定义分页生成的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
。对绝大多数应用来说这不算重大更新,但是,如果你的应用绝对依赖于不是通过队列任务从数据库重新获取的集合,那么就要验证这一改动对应用没有负面影响。
后台woker
在使用Artisan命令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
事件数据修改
多个队列任务事件如JobProcessing
和JobProcessed
将不再包含$data
属性,你需要更新应用调用$event->job->payload()
来获取对应数据。
失败任务表
如果你的应用有了failed_jobs
表,需要添加exception
字段到这张表,exception
字段应该是TEXT
类型,用于保存导致队列任务失败的异常字符串。
在传统风格队列任务上序列化模型
通常,Laravel的队列任务通过传递任务实例到Queue::push
方法添加到队列,不过,一些应用会通过如下这种传统的方式添加任务到队列:
Queue::push('ClassName@method');
如果你在使用这种语法,Eloquent模型将不再会被自动序列化然后通过队列重新获取,如果你想要Eloquent模型继续被队列自动序列化,需要在任务类上使用Illuminate\Queue\SerializesModels
trait并使用新的方法将任务推送到队列:
Queue::push(new ClassName);
路由
资源路由参数默认是单数
之前版本的Laravel中,使用Route::resource
注册的路由参数并没有“单数化”,这可能会在注册路由模型绑定的时候引起一些非预期的行为,例如,给定如下Route::resource
调用:
Route::resource('photos', 'PhotoController');
show
路由的URI将会定义如下:
/photos/{photos}
在Laravel 5.3中,所有资源路由参数默认都是单数化的,因此,同样调用Route::resource
,将会注册URI如下:
/photos/{photo}
如果你想要继续维护之前版本的行为而不是自动单数化资源路由参数,可以在AppServiceProvider
中这样调用singularResourceParameters
方法:
use Illuminate\Support\Facades\Route; Route::singularResourceParameters(false);
资源路由名称不再受路由前缀影响
使用Route::resource
的时候URI前缀将不再影响分配给路由的路由名称,如果在Route::group
中使用Route::resource
时调用了指定的prefix
选项,则需要检查所有对route
辅助函数的调用以验证不再追加URI的prefix
到路由名称。
如果这一改动导致同一名称下有两个路由,可以在调用Route::resource
的时候使用names
选项为给定路由指定一个自定义路由,更多信息请查看完整的路由文档。
验证
表单请求异常
如果一个表单请求验证失败,Laravel现在会抛出一个Illuminate\Validation\ValidationException
实例而不是HttpException
实例,如果你手动捕获了表单请求的HttpException
实例,需要修改catch
区块代码为捕获ValidationException
。
支持空的原生数值
当验证数组、布尔值、整型、数字、字符串时,null
不会被当作有效值,除非在约束条件中设置包含nullable
:
Validate::make($request->all(), [ 'string' => 'nullable|max:5', ]);
12 Comments