从Laravel4升级为Laravel5
利用composer从新开始安装一个Laravel5的应用十分简单(当然前提是网络畅通,装好composer而言的...),只要执行:composer create-project laravel/laravel my-project-name-here dev-develop --prefer-dist
命令就可以了。但是如果想将一个已有的Laravel4应用升级呢?
你可能认为只需要这么做:升级Composer依赖包,然后手工修改发生变化的文件。相当少一部分小伙伴是通过这种方式完成了升级,这也是可以的——但是在修改过程中那有很多琐碎的问题需要注意,而Taylor(Laravel创始人)也公开表示,他认为最好的升级方法还是直接全部复制文件然后再修改,这也是我们准备要用的方法。
第一次升级花了我3个小时(因为我一边在写这个文章),而第二次我只花了1小时。SaveMyProposals
(译者注:作者自己的一个原来基于Laravel4的项目)不是十分复杂,也希望这个文章能帮助你更快完成升级
##开始,一些目录和文件的配置##
本文将从升级SaveMyProposals
项目开始,首先,我进入目录~/Sites/savemyproposals
把一个新网站(一个新的空的Laravel5包)和一个旧网站(从github获得的基于Laravel4.2的SaveMyProposals)放在一起,将一个新的SaveMyProposals从github下载到平行的目录l5smp。我将在新的目录下将文件升级为laravel5,而不是在我之前的工作目录,以保证我没有遗漏任何git-ignored状态的文件
cd ~/Sites
git clone git@github.com:mattstauffer/savemyproposals.git l5smp //从github获取 savemyproposals
cd l5smp
git checkout -b features/laravel-5 //创建并切换到features/laravel-5分支
好,现在我们清理我们的目录。我希望除了.git外,删除其他任何文件。这是我能想到最快的清理方法,但如果谁有更好的方法也欢迎贡献出来:
cd ~/Sites/l5smp
rm -rf *
rm .gitattributes
rm .gitignore
当然,如果你有任何文件仍然没删干净——例如.scrutinizer.yml——将它们也删除。我们将在后面的步骤将它们拷贝回来。记住,除了.git你不要在你的目录中留任何东西
我们已经准备好升级环境,将在这目录(l5smp)将SaveMyProposals升级为Laravel5了!如果你像我一样,希望一个干净的节点便于恢复,可以做一次git提交:
说明:如果你做了提交,你将失去所有你打算拷贝回来的文件的版本延续性。当然,我们为了保持版本延续性,可以在之后使用git merge --squash命令合并这次提交。
好的,我们将在这目录放置Laravel5的文件。感谢 Isern Palaus (@ipalaus) 在这一步给了我一个十分简便的方法
git remote add laravel https://github.com/laravel/laravel.git
git fetch laravel
git merge laravel/master --squash
git add .
git commit -am "Bring in Laravel 5 base."
composer install
你应该检查一下,用下面的命令确认这个应用(虽然是空的)正常工作了:
php -S localhost:8090 -t public/
在浏览器中查看http://localhost:8090/(替换为你自己网站对应地址),如果你看到这个画面,我们就做对了:
现在,把文件一一拷贝到Laravel5的包中,开始升级。我是用 iTerm 2把目录并排打开,然后将旧网站OLD目录(~/Sites/savemyproposals)下的文件,将它们一一拷贝到新网站NEW目录(~/Sites/l5smp)里。我将文件夹看做OLD和NEW,OLD是我的laravel4代码目录,而新的是空的Laravel5安装包,记住他们的代号,下面开始拷贝:
##PSR-4命名空间##
If you already have a top-level PSR-0/PSR-4 namespace set up, like I did for SaveMyProposals, you’ll want to use the new app:name Artisan command. 如果你就像我在SaveMyProposals所做那样,已经建立一个顶级的PSR-0/PSR-4命名空间,你需要用新的app:name Artisan命令:
php artisan app:name SaveMyProposals
##你的域文件夹##
如果你跟着一些社区论坛学习时,建立过一些最高级目录(改变原来的目录结构),或在以自己重新命名了最高级命名空间——例如我的app/SaveMyProposals
就在我的PSR-0目录下
解决这个问题最简单的方法就是将这个文件夹下所有文件移到你的app
文件夹里,然后将他们放在你已经建立的命名空间下(例如这里的SaveMyProposals)。完工。
##composer.json依赖包##
你需要祈祷你的所有依赖包都已经升级并支持Laravel5(译者注:例如Sentry2就不支持Laravel5,而Sentry3听说是收费了,悲剧)。将旧的composer.json
所有依赖项和其他个人配置,一一拷贝到新的composer.json
中。
现在,试试使用composer update
升级,看看你的祈祷有没有用吧。
##app/ 目录下##
###命令(app/commands)目录###
将app/commands
的内容全部移到app/Console/Commands
里
你可以为commands文件分配命名空间,或者不分配而将其目录添加到composer.json->autoloader->classmap中,让composer自动加载。
请注意,在Laravel5中默认调用handle()方法执行命令,但事实上,Laravel对于fire()(旧版本),或handle()(新版本)都是会调用的。
将所有命令的绑定配置从start/artisan.php
移到app/console/kernel.php
里的$commands
数组,在这注册所有命令的绑定。
###配置(app/config)目录###
请看下面的Configureation目录
###控制器(app/controllers)目录###
将app/controllers
的内容全部移到app/Http/Controllers
中
要么为你的controllers(及目录下的文件)分配命名空间,要么从抽象类app/Http/Controllers/Controller.php
删除命名空间,并在composer->autoload->classmap下添加app/Http/Controllers
的目录
###数据库迁移文件和填充文件(Database Migrations & Seeds)###
将app/database
的内容全部移到database
里
如果你已经有user表的迁移文件,且你确定你已经添加了remember_token
字段(在版本4.1.26添加),就可以删除Laravel5的database/migrage
下的2014_10_12_00000_create_users_table
文件。但必须保留password_reset
迁移文件,这是Laravel5中新添加的。
###过滤器(filters)目录###
Laravel5中过滤器(filters)的功能全都以中间件(Middleware)的模式实现。但你也仍可以使用你旧的过滤器文件,只需要把原来的过滤器都贴到app/Providers/RouteServiceProvider.php的boot()里,例如:
// app/filters.php
Router::filter('shall-not-pass', function() {
return Redirect::to('shadow');
});
变成这样:
// app/Providers/RouteServiceProvider@boot()
$router->filter('shall-not-pass', function() {
return \Redirect::to('shadow');
});
注意你不需要移动任意系统默认过滤器,他们已经被移植了,不过现在变为中间件的模式而已。
###多语言(app/lang)###
将app/lang
的内容全部移到resources/lang
里
###模型(app/models)目录###
在社区里面多次提及,Laravel5已经去除了模型(models)文件夹的概念。如果你想保留models目录只需要在应用的app
目录下创建一个models
目录,并把目录地址添加进在composer.json->autoload->classmap中,如下:
"autoload": {
"classmap": [
"database",
"app/models"
]}
我们可以看到在Laravel5中自带的User.php
被放到app
目录下,所以你也可以将你的模型文件都放在app
这个顶级目录下(例如SaveMyProposals/Conference
就是conference
模型)
####软删除####
如果你在模型文件中使用了软删除标记SoftDeletingTrait
,需要将标记改为SoftDeletes
###路由(app/routers)目录###
将app/routes.php
的内容全部移到app/Http/routes.php
中
你需要调整所有以前使用before绑定过滤器的路由,例如,before => auth
需要改为 middleware => auth
。
###启动(app/start)目录###
artisan.php
需要参照上述commands
目录,全部移到command
进行绑定
global.php
对于很多人来说就像个杂物箱。所有这里的配置都应该改为使用服务提供者service provider
配置,但如果你不想一一做去改,也可以在SaveMyProposals\Providers\AppServiceProvider
中的register()
方法中注册
###测试(app/test)目录###
将app/tests
的内容全部移到tests
中
###视图(app/view)目录###
将app/views
的内容全部移到resources/views
中
##修改控制器(controllers),命令(commands)等命名空间等##
###修改控制器(controllers)的命名空间###
如果你的旧代码中没有为控制器设定命名空间,你可以选择添加或者不添加命名空间:
如果你想添加命名空间,只需要在每一个控制器添加上use SaveMyProposals\Http\Controllers
如果你不想这么做,需要修改app/Providers/RouteServiceProvider.php
,将protected $namespace
改为null
(这个属性相当于所有controller命名空间的前缀),然后将controllers
的目录添加到composer.json->autoload->classmap里,接着编辑RouteServiceProvider.php
的map()
方法,将$this->loadRoutesFrom
整行替换为:
include app_path('Http/routes.php');
注意:如果你修改了控制器的命名空间,所有的内部定义facade将失效。最简单的方法其实还是使用没有命名空间的控制器。如果你还是修改了命名空间,你将看到一些类似
Class 'SaveMyProposals\Http\Controllers\Auth' not found..
的错误。这时你需要在每个控制器开头添加命名空间use Auth, use Session
,等等,或者只是为每个添加上\
。(例如将Session::flash('stuff', 'other stuff');
转换为to \Session::flash('stuff', 'other stuff');
)
###修改artisan commands命名空间###
就像控制器的修改方式那样,你可以选择添加或不添加命名空间。为artisan commands
添加命名空间的方法上述为控制器添加命名空间的方法类似。如果不想添加命名空间,你需要修改app/Console/Kernel.php
中的$commands
属性,然后在composer.json->autoload->classmap中加上app/Console/Commands
目录
##引导项(bootstrap)目录##
如果你在引导项目录中做了部分个人配置,甚至只是在start.php
中,你都得把它们删掉。注意detectEnvironment在Laravel5发生了改变,所以不用管任何环境检测的内容,你将对这部分重新设置(见下面配置.env文件的方法)
##公共资源(public)目录##
你可以在NEW目录的public
下将除了index.php
外所有文件删除,然后在OLD目录下的public
中将所有文件拷过来
你可能注意到Laravel5将less的源文件放在resources/assets/less
,所以如果你想遵循这种结构,你可以将sass或者less文件和其他资源文件放在这。但你不是一定要这么做,所以这里我们就不演示了。
##其他顶级目录文件##
这需要你自己决定,例如是readme.md
, .scrutinizer.yml
, .travis.yml
, travis.php.ini
, package.json
, gulpfile.js
等等。注意Laravel中默认自带package.json
和gulpfile.js
,所以你在覆盖的时候需要检查一下它们
当然,记得拷贝所有你自己应用产生的文件,例如.gitignore
, .gitattributes
,又或者phpunit.xml
。
##配置(configureation)##
###.env.local.php => .env###
我将.env.local.php
从OLD目录拷贝到了NEW目录。然后我将它从一个php数组转换成.env
格式,从这样:
<?php return ['key' => 'value'];
变成
key=value
我会将我认为需要设置的每个值设置到.env里:
key=valueHere
我对框架内部需要使用的值进行如下配置:APP_ENV
(设置为"local"
),APP_DEBUG
(设置为true
), APP_KEY
(设置为我的密钥), DB_HOST
、DB_DATABASE
、DB_USERNAME
、DB_PASSWORD
设置为适当的数据库配置,而CACHE_DRIVER
和SESSION_DRIVER
设置为'file'
##配置文件##
抛弃以往local
,production
,staging
等配置文件的概念,抛弃.env.local.php
,.env.staging
等想法。Laravel5里配置文件的加载,环境监测已经变得十分简单。
所有通用配置文件都应该放在我们最熟悉的config
目录下。
所有特定环境的配置文件都应该放在.env
里,而且应该被git所忽略。
.env.example
应该写出所有的、分布在各个.env
文件中的、需要配置的项。
所以,从你的OLD文件中拷贝出通用的值放到NEW目录的config
目录下,然后可变的值放在.env
和.env.example
文件里。
##验证和用户##
使用你原来版本的User
模型时最方便的,但是如果这样行不通,这有一些解决方法
从你的代码删除以下内容:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
添加以下内容到你的代码:
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
删除UserInterface
和RemindableInterface
接口文件
如果你用了上述接口文件,从你的代码和类声明中删除Illuminate\Auth\Reminders\RemindableTrait
和Illuminate\Auth\UserTrait
实现以下接口
implements AuthenticatableContract, CanResetPasswordContract
在类声明中包含以下内容
use Authenticatable, CanResetPassword;
最后,改变User
模型的命名空间为你app目录的命名空间,或者在config/auth.php
中改变model
属性到正确的命名空间。(例如,用User
代替SaveMyProposals\User
)
最后的最后,如果你用了你自己的User
模型,那么就删掉app/user.php
文件
##Form & HTML Helpers##
###报错“class 'Form' not found”###
如果你用了Form & HTML Helpers,你将看到一个class 'Form' not found
的错误(在使用Html时也会看到)。请修改composer.json
,添加"illuminate/html": "~5.0"
你还需要修改配置让Facade和服务提供者生效。编辑config/app.php
,然后添加这个语句到'providers'
数组
'Illuminate\Html\HtmlServiceProvider',
添加这些到'aliases'
数组
'Form' => 'Illuminate\Html\FormFacade',
'Html' => 'Illuminate\Html\HtmlFacade',
##{{ }} 的变化##
Blade模板中的原生HTML输出(不作转义)的功能,符号从{{
变为了{!!
。为了处理这个问题需要你查找和替换任何一个你知道的直接输出html的地方,例如是Laravel form helpers,就需要将{{
和}}
分别替换为{!!
和!!}
。而其他地方仍然保留{{
和}}
。{!!
现在应该开始作为Blade模板默认的输出符号。
如果因为某些原因你需要用就得用回旧的blade
符号(例如懒的做替换操作),你可以自己去定义。只要添加下列代码到AppServiceProvider@register()
里:
\Blade::setRawTags('{{', '}}');
\Blade::setContentTags('{{{', '}}}');
\Blade::setEscapedContentTags('{{{', '}}}');
注意这样你将改变原生的输出符号,{{--
作为注释又不再可用了。
##最后的清理##
如果你之前想我一样做了commit
,你现在可以用git merge --squash
将他们作合并了。然后用git log看你做了多少次提交,我有3个。然后执行git rebase -i HEAD~3
(用你的数字代替3)
这将启动git,如果你对git squash不太熟悉,可以看看我的tutorial on Squashing Git Commits文章里的介绍。
##其他方面的问题##
###修改了命名空间的控制器里的Façades###
因为所有东西都重新做了命名空间,所有你的控制器里的View::make()
(或所有其他被使用的facede)都将失效,因为他们不能找到从顶级命名空间找到View
,Auth
等等。解决这个问题最简单的方法可能是在文件顶部加上use View
,虽然哪还有很多其他更“单纯”的方法
###Whoops样式报错处理器###
如果你希望用回Whoops
样式的报错处理器,在这里我有一个更换的方法
###依赖包###
Laravel5中依赖包的工作方式发生了很大变化,所以可能还有很多小问题需要解决。如果你执行过程中发现了这些小问题,欢迎留下评论告诉我,让我这个解决方案更加完善。目前为止,Ryan Tablada已经警告说:“准备好迎接‘function "package" does not exist’
的问题吧!”
###有没有什么包是没有动过的...###
有很多包都被改变过,特别是Laravel自有的一些包。如果硬要找,可能这个版本里bugsnag-laravel
是仅有没有动过的了...
##结语##
这只是一个小教程,很多小问题没有说到位,因为我只有用一个特定的网站做示例。所以,这种行为不符合我的初衷,我将要打开GitHub中的评论提供修改/更新/等。
正如你可以看到,那有很多很琐碎的东西,但实际上这已经是一个非常简单而快速的升级方法了,考虑到我们以后的升级基础版本就是Laravel 5,快去升级吧!
##故障排除列表##
###Eloquent模型###
如果你看到这个错误:
PHP Fatal error: Class 'Eloquent' not found in /path/to/YourModel.php
这是因为你的模型没有继承\Eloquent
。只需要在你的模型里添加上这个use,就能解决问题:
use Illuminate\Database\Eloquent\Model as Eloquent;
###String Given###
如果捕获到致命错误:
Argument 1 passed to Illuminate\Foundation\Application::__construct() must be an instance of Illuminate\Http\Request
... 你需要执行 composer install.
###Call to a member function domain() on a non-object ###
如果你看到这个错误:
Call to a member function domain() on a non-object
这是因为你的路由跳转动作没有正确连接。例如,如果你跳转一个名为"signup"
的路由但你却没有这个名字的路由,就会报这个错
更可能因为升级为Laravel5了。这会在你任意有或没有命名空间的控制器中发生。
###Illuminate\Session\TokenMismatchException ###
很可能在你的日志里,你会看到Illuminate\Session\TokenMismatchException
这个错误。这是因为默认情况下laravel5是为所有路由开启CSRF( Cross-site request forgery跨站请求伪造)
保护的。你如果想让部分路由去除CSRF保护,可以在App\Http\Kernel
将全局中间件$middleware
数组里的'App\Http\Middleware\VerifyCsrfToken'
移到$routeMiddleware
数组里,让它成为一个可选项;或者你调整包括AJAX
在内所有表单,让他们都适用于CSRF
。
原文地址:https://mattstauffer.co/blog/upgrading-from-laravel-4-to-laravel-5
本文为Matt Stauffer根据自己一个基于laravel4的项目SaveMyProposals,升级到laravel5版本的过程而编写。由于文章比较长且本人才疏学浅,翻译上如有不当请指出,谢谢!