Maison >php教程 >php手册 >从CakePHP 1.3升级到2.5,cakephp1.3升级2.5

从CakePHP 1.3升级到2.5,cakephp1.3升级2.5

WBOY
WBOYoriginal
2016-06-13 09:27:591511parcourir

从CakePHP 1.3升级到2.5,cakephp1.3升级2.5

从CakePHP 1.3升级到2.5

摘要:最近把一个CakePHP 1.3的项目升级到了2.x,当然就用最新的版本2.5.3了,结果基本满意。本文记录了升级的过程,包括使用的工具,遇到的问题和相应的解决方法。

这篇文章涉及的内容要求至少有CakePHP中级水平,如果你是刚开始使用CakePHP,建议先不要作这样的尝试,否则遇到问题都不知道怎么解决。


 

目录

1. 为什么要升级

2. 项目概况

3. 使用的工具

4. 升级的过程

5. 升级之后遇到的问题及解决方法

A. 参考资料


 

1. 为什么要升级

升级到最新版本有很多好处,可以得到最新的更新和功能,可以使用DebugKit这样的调试工具,可以使用View Block方便地把CSS和JavaScript放在页面中你希望的地方,而不再痛苦地受限于旧的方式,等等。View Block一直是我最希望使用的特性。

2. 项目概况

这个项目的开发大致起始于2012年底,我从2013年中开始参与,到2014年中,所有用户要求的功能基本都完成了。我参与了大概1年左右,只是利用业余时间进行。代码一开始是抄自于一个CakePHP 1.3的项目,而没有使用当时最新的2.x版本,这也使得许多开发工作不能利用框架最新的特性和工具,延长了开发周期。可以说,这个项目从开始就做了错误的选择。先后参与的开发人员前后有6个人之多,多数是临时抓来的,大部分人做一段时间之后就会离开,有些功能甚至没有完成就走人了。而且大家对CakePHP这个框架没有深入的了解,导致这个项目的代码没有一致性,也缺乏统一的计划、架构和规范,没有单元测试。总之,项目的代码质量是不能令人满意的。这些恐怕是大部分业余项目难以避免的问题。

幸好,这个项目不算特别复杂,计有:

  • 数据库有36张表
  • 19个控制器(Controller)
  • 33个模型(Model)
  • 63个视图(View)
  • 2个插件(Plugin)
  • 当然还有其他一些东西

通过这些数据可以看出这个项目的规模,应该说是个中小型网站吧。

3. 使用的工具

升级只使用了2个工具,首先是官方的Upgrade Shell,以及DerEuroMark的Upgrade Plugin。

4. 升级的过程

真正动手升级之前我花了一些时间阅读参考资料中列出的文档,实际的升级过程前后总共花了4天时间,不过这里面相当一部分时间用于升级后的测试、以及寻找解决问题的方法。我毕竟从1年前才开始真正使用PHP和CakePHP来开发实际使用的网站,而且只是利用业余时间,所以时间有限,很多东西也都是边做边摸索学习,主要目标是要完成用户需求所要求的功能,来不及了解CakePHP框架的各个方面。如果你有相应的经验,或者有解决下面所涉及问题的这些知识,这个过程会快许多。

4.1 备份

首先,确保升级之前,应用程序运行良好,做好代码和数据的备份。如果没有备份,请就此打住!!!

我使用Git(TortoiseGit)做源码控制,这让我可以随时回到过去某一个时间点。数据库使用的是MySQL,升级之前也要做好备份。如果升级过程出了问题,进行不下去,备份让你可以恢复到开始升级之前的状态;如果没有备份,那你可就进退维谷了。

4.2 更新CakePHP的核心库到2.x

这个项目在升级前的目录结构,如下图所示,

图中,cake为CakePHP 1.3的核心库,app是应用程序代码。

下载最新的CakePHP,我用的是2.5.3,打开压缩包,如下图所示。

图中的lib目录就是CakePHP的核心库,把这个lib目录拷贝到根目录下,然后删除1.3的cake目录,得到如下图所示的目录结构。

图中的lib\Cake目录就是CakePHP 2.x的核心库。

4.3 准备升级工具Upgrade Shell

Upgrade Shell是CakePHP核心的一部分,位于lib\Cake\Console\目录下,只需确保能够运行CakePHP Console可执行文件就可以了,这可以参考CakePHP Console的文档。如下图所示,

图中的cake是*nix下的可执行文件,cake.bat是Windows下的可执行文件。我采用的做法,是参考了Upgrade Shell的文档,把lib\Cake\Console\目录拷贝到app目录下,这样只是执行的命令行路径有所不同,结果是一样的,如下图所示。

图中的app\Console\就是我采用的Console路径。

4.4 准备升级工具Upgrade Plugin

下载DerEuroMark的Upgrade Plugin,解压之后拷贝到app\Plugin\目录下,如下图所示。

4.5 运行Upgrade Shell

按照Upgrade Shell的文档,可以运行.\Console\cake Upgrade.Upgrade all,这会执行所有的升级任务;当然也可以逐个执行单个任务。因为这是官方的工具,我就所有的任务一起运行了。

我的操作系统是Windows 7,在命令行下进入app\目录,然后运行.\Console\cake upgrade all,结果如下:

D:\...\app>.\Console\<span>cake upgrade all


Welcome to CakePHP v2</span>.5.3<span> Console
---------------------------------------------------------------
App : app
</span><span>Path</span>: D:\...\app\<span>
---------------------------------------------------------------
Running tests
Running locations
Upgrading locations </span><span>for</span><span> plugin contact_us
Upgrading locations </span><span>for</span><span> plugin file_upload
Moving </span><span>View</span>\handler to <span>View</span>\<span>Handler
Moving </span><span>View</span>\helpers to <span>View</span>\<span>Helpers
Moving </span><span>View</span>\layouts to <span>View</span>\<span>Layouts
Upgrading locations </span><span>for</span><span> plugin popup
Moving </span><span>View</span>\elements to <span>View</span>\<span>Elements
Moving </span><span>View</span>\helpers to <span>View</span>\<span>Helpers
Upgrading locations </span><span>for</span><span> app directory
Moving config to Config
Moving Config</span>\schema to Config\<span>Schema
Moving </span><span>View</span>\contacts to <span>View</span>\<span>Contacts
Moving </span><span>View</span>\elements to <span>View</span>\<span>Elements
Moving </span><span>View</span>\errors to <span>View</span>\<span>Errors
Moving </span><span>View</span>\group to <span>View</span>\<span>Group
Moving </span><span>View</span>\help to <span>View</span>\<span>Help
</span>... ...
... ...<span>
Running components
Done updating D:</span>\...\app\Controller\Component\CropComponent.<span>php
Running exceptions
</span>Done updating D:\...\app\Controller\AppController.php<br />Done updating D:\...\app\Controller\CommentController.php<br />Done updating D:\...\app\Controller\ContactsController.php<br />Done updating D:\...\app\Controller\DataConversionController.php<br />Done updating D:\...\app\Controller\GroupPostController.php<br />Done updating D:\...\app\Controller\GroupTalkController.php<br />Done updating D:\...\app\Controller\HelpController.php<br />... ...

:这里看到的\...\是我省略了真实路径。

:这个结果有1815行,故只是截取了首尾若干行。

小窍门:一些升级任务,比如locations,会改变目录和文件名称,比如把app\config (注意是小写)改名为app\Config (注意是大写),详细情况可参考CakePHP 2.0 Migration Guide中File and Folder naming一节。在Windows下,由于目录名和文件名不区分大小写,所以目录名仅仅大小写的改变,在Windows看来并不认为目录名发生了变化,所以不会引起git对目录进行重命名。这个问题可以通过2次git mv命令(使用TortoiseGit就是rename...)来强制git重命名。运行升级任务locations之后,在Windows Explorer中看已经是app\Config (注意是大写)了,但在git库(即TortoiseGit->repo-browser)中,看到目录还是app\config (注意是小写)。这时,先在Windows Explorer中把app\Config改名回app\config。然后进行2次git重命名(TortoiseGit->Rename...),先把config改名为config2(随便增减一些字符都行),然后再次用git重命名把config2改为Config,最后再git commit,这样git库中就也是app\Config了。

4.6 运行Upgrade Plugin

虽然Upgrade Plugin来自CakePHP的核心开发者DerEuroMark,但仍然不是CakePHP官方发布的工具,故相比Upgrade Shell存在较高的风险。所以我采用的是逐个运行任务的方式,谨慎一些比较好,毕竟这是我第一次升级CakePHP。每执行完一个任务,我就git commit,保存每次任务的变化。这样就可以通过git的历史知道每次任务改变了哪些文件,作了什么变 化。以后如果发生问题,也可以缩小范围,知道是哪个任务做的改变引起了问题,便于积累经验。

在逐个运行升级任务之前,注意Upgrade Plugin文档中推荐的顺序,故此我先执行cake Upgrade.Upgrade locations。

在命令行下进入app\目录,然后运行.\Console\cake Upgrade.Upgrade locations,结果如下:

D:\...\app>.\Console\cake Upgrade.<span>Upgrade locations

Welcome to CakePHP v2</span>.5.3<span> Console
---------------------------------------------------------------
App : app
</span><span>Path</span>: D:\...\app\<span>
---------------------------------------------------------------
Moving locale to Locale
Moving config to Config
Moving Config</span>\schema to Config\<span>Schema
Moving </span><span>View</span>\contacts to <span>View</span>\<span>Contacts
Moving </span><span>View</span>\elements to <span>View</span>\<span>Elements
Moving </span><span>View</span>\errors to <span>View</span>\<span>Errors
Moving </span><span>View</span>\group to <span>View</span>\<span>Group
Moving </span><span>View</span>\help to <span>View</span>\<span>Help
Moving </span><span>View</span>\helpers to <span>View</span>\<span>Helpers
Moving </span><span>View</span>\index to <span>View</span>\<span>Index
Moving </span><span>View</span>\job to <span>View</span>\<span>Job
Moving </span><span>View</span>\layouts to <span>View</span>\<span>Layouts
Moving </span><span>View</span>\messages to <span>View</span>\<span>Messages
Moving </span><span>View</span>\news to <span>View</span>\<span>News
Moving </span><span>View</span>\os to <span>View</span>\<span>Os
Moving </span><span>View</span>\pages to <span>View</span>\<span>Pages
Moving </span><span>View</span>\scaffolds to <span>View</span>\<span>Scaffolds
Moving </span><span>View</span>\uc to <span>View</span>\<span>Uc
Moving </span><span>View</span>\users to <span>View</span>\<span>Users
Moving </span><span>View</span>\video to <span>View</span>\<span>Video
Removing empty folder </span>\controllers

我又继续运行了其它命令,所有命令如下面列表所示。注意,有些升级任务没有引起任何变化,故记录为no change。

[x] .\Console\cake Upgrade.Upgrade locations<br />[x] .\Console\cake Upgrade.Upgrade webroot<br />[x] .\Console\cake Upgrade.Upgrade routes<br />[x] .\Console\cake Upgrade.Upgrade database<br />[x] .\Console\cake Upgrade.Upgrade basics<br />[x] .\Console\cake Upgrade.Upgrade helpers: no change<br />[x] .\Console\cake Upgrade.Upgrade request<br />[x] .\Console\cake Upgrade.Upgrade configure: no change<br />[x] .\Console\cake Upgrade.Upgrade constants: no change<br />[x] .\Console\cake Upgrade.Upgrade controllers<br />[x] .\Console\cake Upgrade.Upgrade components: no change<br />[x] .\Console\cake Upgrade.Upgrade exceptions: no change<br />[x] .\Console\cake Upgrade.Upgrade views<br />[x] .\Console\cake Upgrade.Upgrade stylesheets<br />[x] .\Console\cake Upgrade.Upgrade legacy<br />[x] .\Console\cake Upgrade.Upgrade constructors: no change<br />[x] .\Console\cake Upgrade.Upgrade paginator: no change<br />[x] .\Console\cake Upgrade.Upgrade name_attribute<br />[x] .\Console\cake Upgrade.Upgrade methods<br />[x] .\Console\cake Upgrade.Upgrade cake13: no change<br />[x] .\Console\cake Upgrade.Upgrade cake20: no change<br />[x] .\Console\cake Upgrade.Upgrade cake21<br />[x] .\Console\cake Upgrade.Upgrade cake23<br />[x] .\Console\cake Upgrade.Upgrade cake24: no change<br />[x] .\Console\cake Upgrade.Upgrade cake25<br />[x] .\Console\cake Upgrade.Upgrade validation: no change<br />[x] .\Console\cake Upgrade.Upgrade estrict: no change<br />[x] .\Console\cake Upgrade.Correct stable<br />[x] .\Console\cake Upgrade.Convert arrays -v

应当注意的是,在运行每个命令之前,最好还是读一下源代码,知道每个升级任务做的是什么改变。比如最后一个命令cake Upgrade.Convert arrays -v,这个升级任务把数组由下面的长格式:

<span>array</span>('admin', 'api')

变成了短格式:

['admin', 'api']

这个任务的源代码位于app\Plugin\Upgrade\Console\Command\ConvertShell.php的arrays()方法中。这是我后悔运行了的一个任务,因为数组的短格式是在PHP 5.4.0中增加的,改变的文件又相当多。做了这个变化后,代码就会要求PHP的版本是5.4.0或者更高,而CakePHP2.x只要求PHP 5.2.8,这样就提高了对运行环境的要求,缩小了代码的适用范围,如果将来遇到迁移服务器的情况,在选择运行环境时,就会少了很多选择,也可能意味着不得不付出更高的服务器空间租用费用。所以,建议这个升级任务,除非有必要,不要执行。

到此,所有升级工具能做的事情都已经做了。似乎升级大业已经完成了,后来才知道,这才进行了不到一半,真是行百里者半九十。

5. 升级之后遇到的问题及解决方法

5.1 白屏

该试着运行一下应用程序了。当我打开首页的时候,我惊呆了,白屏!坏了!由Firebug知道服务器返回的是错误500,这意味着服务器错误,但仍然不知道服务器上哪里出问题了,当时真有些不知所措,这已经是晚上11点多了,在QQ群里问了一圈,也不得要领。试了各种调试方法,PHP的错误日志,CakePHP的日志,都没有任何记录。这一晚没睡好!

第二天,经过文档的阅读以及很多思考,我想到,升级工具已经帮我做了很多事情,但仍然有些部分是升级工具没有做的,这恐怕要我自己手工做了,毕竟工具不是万能的,还有不少事非得自己动手不可。

我先着手的是下面这些配置文件:

app\Config\bootstrap.<span>php
app</span>\Config\core.php

我逐个配置比较1.3和2.x的两个版本,一些配置取消了,一些配置是新增的。改了个七七八八,但仍然是白屏,不过这项工作并不是没用的,这毕竟还是必不可少的。

我再按照更改目录名称的小窍门,改了不少git库中的目录名大小写,不过我也知道这对于白屏没有帮助,因为git库不会直接影响程序运行结果。不过这仍然是保证git库一致性必须的工作。

最终,我想到了应用程序的入口,index.php。整个目录结构中总共有3个index.php:

index.<span>php
app</span>\index.<span>php
app</span>\webroot\index.php

比较1.3和2.x的版本,其中,根目录下的index.php和app\webroot\index.php有实质性的变化,另外一个app\index.php只是注释的变化。

改完3个index.php后,首页总算是能够显示了,只是还是很不正常,但CakePHP的日志也有了,这样就可以通过日志准确定位错误发生的位置了。

5.2 MissingPluginException

下面要对付的错误在CakePHP的日志error.log中是这样记录的:

2014-07-23 17:44:01 Error: <span>[</span><span>MissingPluginException</span><span>]</span><span> Plugin Popup could not be found.
Exception Attributes: array (
  'plugin' </span>=> 'Popup',<span>
)
Request URL: /<br />Stack Trace:</span>

后面还有更详细的Stack Trace。

这个Popup插件,我之前用的是1.5版本,经过这将近1年已经升级到2.0版本了。我进行了升级,这个问题就解决了。

我担心Popup插件2.0发布之后,CakePHP又进行了升级,而Popup插件却没有做相应的升级,所以又运行了下面的升级任务:

D:\...\app>.\Console\cake Upgrade.Upgrade locations -p Popup

没有文件发生变化,说明Popup插件2.0已经符合2.5.3的要求了。

5.3 Unsupported operand types in FormHelper.php

下一个错误:

Fatal Error (1): Unsupported operand types in <span>[</span><span>...\html\lib\Cake\View\Helper\FormHelper.php, line 2477</span><span>]</span>

这一行代码位于FormHelper::dateTime()方法。这个错误是由于从1.3到2.5,FormHelper的一些方法去掉了$select参数,这正包括FormHelper::dateTime(),其原型从:

FormHelper::dateTime(<span>$fieldName</span>, <span>$dateFormat</span> = 'DMY', <span>$timeFormat</span> = '12', <span>$selected</span> = <span>null</span>, <span>$attributes</span> = <span>array</span>())

变成了:

FormHelper::dateTime(<span>$fieldName</span>, <span>$dateFormat</span> = 'DMY', <span>$timeFormat</span> = '12', <span>$attributes</span> = <span>array</span>())

我对应用程序的代码做的相应变化就是,从:

<span>echo $this->Form->dateTime('Voucher.expired', 'YMD', '24', <span>strtotime('+15 day'),</span> array(<br />    'label' => false,<br />    'minYear' => date('Y'),<br />    'maxYear' => date('Y') + 1,<br />    'empty' => false<br />));</span>

改成:

<span>echo $this->Form->dateTime('Voucher.expired', 'YMD', '24', array(<br />    'selected' => strtotime('+15 day'),<br />    'label' => false,<br />    'minYear' => date('Y'),<br />    'maxYear' => date('Y') + 1,<br />    'empty' => false<br />));<br /></span>

5.4 MissingComponentException

这个错误如下:

Error: <span>[</span><span>MissingComponentException</span><span>]</span> Component class UploadFileComponent could not be found.

原因在于,从2.0开始,所有的组件都必须继承自Component基类,而在1.3中没有这个要求。

5.5 Cannot use object of type ComponentCollection as array

这个错误是:

Error: Fatal Error (1): Cannot use object of type ComponentCollection as array in <span>[</span><span>...\app\Plugin\FileUpload\Controller\Component\UploadFileComponent.php, line 61</span><span>]</span>

原因是Component的构造函数也发生了变化,在1.3中,是:

<span>function</span> __construct(<span>$options</span> = <span>null</span><span>) {
}</span>

而在2.x中,这变成了:

<span>function</span> __construct(ComponentCollection <span>$collection</span>, <span>$options</span> = <span>null</span><span> ) {
}</span>

这是因为,从2.0开始,控制器(Controller)不再直接连接控件(Component),而是通过ComponentCollection(即Controller::$Components)来操纵它的控件,详见2.0 Migration Guide中的Controller一节。

请对所有控件(Component)的构造函数做相应的修改。

5.6 "Indirect modification" for pagination

错误信息为:

Notice (8<span>):
Indirect modification of overloaded property PostsController::$paginate has no effect </span><span>[</span><span>APP/Controller/PostsController.php, line 13</span>

这个错误的解释见DerEuroMark博客中“Indirect modification” for pagination一节。较好的做法是采用2.0的语法,不过我匆匆阅读了文档,仍然没有搞明白2.0的语法的含义,就采用了文中提到的简便方法:

<span>class</span> AppController <span>extends</span><span> Controller {
    </span><span>//</span><span>...</span>

    <span>/*</span><span>*
     * The paginate options for this controller
     *
     * @var array
     </span><span>*/</span>
    <span>//</span><span> TODO: upgrade to the new PaginatorComponent syntax</span>
    <span>public</span> <span>$paginate</span> = <span>array</span><span>();

    </span><span>//</span><span>...</span>
}

这就足够消除这个问题提示,并让应用程序正常运行。而我在注释中留下TODO标签,等以后有时间再来改进。我需要尽可能缩短升级所用的时间,因为有可能项目中别的开发者也正在做其他的改动,我升级所花的时间越多,这期间别人做的改动就可能越多,合并的时候发生矛盾的机会就越多。

5.7 JavascriptHelper could not be found

这个错误的日志为:

Error: <span>[</span><span>MissingHelperException</span><span>]</span><span> Helper class JavascriptHelper could not be found.
Exception Attributes: array (
  'class' </span>=> 'JavascriptHelper',<span>
  'plugin' </span>=> false,<span>
)</span>

2.0中,JavascriptHelper已作废,而由JsHelper和HtmlHelper代替,详见2.0 Migration Guide中的XmlHelper, AjaxHelper and JavascriptHelper removed一节。所以,我要做的是,在相应的控制器中用JsHelper代替JavascriptHelper,把:

<span>public</span> <span>$helpers</span> = <span>array</span><span>(
    </span><span>//</span><span>...</span>
    ,'Javascript'<span>
);</span>

改为:

<span>public</span> <span>$helpers</span> = <span>array</span><span>(
    </span><span>//</span><span>...</span>
    ,'Js' => <span>array</span>('Jquery'<span>)
);</span>

5.8 Cannot use isset() on the result of a function call

错误信息:

Error: Fatal Error (64): Cannot use isset() on the result of a function call (you can use "null !== func()" instead) in <span>[</span><span>D:\...\app\Controller\SoldiersController.php, line 175</span><span>]</span>

引起错误的代码为:

<span>if</span> (<span>isset</span>(<span>$this</span>->request->query('email'<span>))) {
}</span>

改为:

<span>if</span> (<span>null</span> !== <span>$this</span>->request->query('email'<span>)) {
}</span>

5.9 用户登录总是失败

这是因为在2.0中,AuthComponent验证用户的方式略有变化,用户代码需要显示调用AuthComponent::login()来验证用户登录信息。原来的代码:

<span>//</span><span> 只是示意</span>
<span>public</span> <span>function</span><span> login() {
    </span><span>if</span> (!<span>$this</span>->request->is('post'<span>)) {
        </span><span>//</span><span> 显示登录表单</span>
    } <span>else</span><span> {
        </span><span>//</span><span> 登录成功</span>
<span>    }
}</span>

需要变成:

<span><span>//<span> 只是示意</span></span><br />public function login() {<br />    if (!$this->request->is('post')) {<br />        <span>//<span> 显示登录表单</span></span><br />    } else {<br />        if ($this->Auth->login()) { <span>// 现在需要显示调用</span><br />            return $this->redirect($this->Auth->redirectUrl());<br />        } <br />    } <br />}</span>

5.10 JavaScript变量由public声明

这是由于在CakePHP 2.0中,废止了对PHP 4的支持,所有的类成员都可以用public、protected和private来声明。Upgrade插件要把视图(View)中的JavaScript变量误当做PHP类成员,而改变了声明,导致了浏览器中JavaScript的错误,这可以从Firebug中看到,如下图所示。

错误的代码为:

<?php $<span>this</span>->Html->scriptStart(['inline' => <span>false</span>]); ?><span>
$(document).ready(</span><span>function</span><span>() {
    </span><span>//</span><span> ...</span>
    public $that = $(<span>this</span><span>);
    </span><span>//</span><span> ...</span>
<span>});
</span><?php $<span>this</span>->Html->scriptEnd(); ?>

很容易地改正为:

<?php $<span>this</span>->Html->scriptStart(['inline' => <span>false</span>]); ?><span>
$(document).ready(</span><span>function</span><span>() {
    </span><span>//</span><span> ...</span>
    <span>var</span> $that = $(<span>this</span><span>);
    </span><span>//</span><span> ...</span>
<span>});
</span><?php $<span>this</span>->Html->scriptEnd(); ?>

5.11 error in $this->Js->scriptBlock();

这个发生在视图(View)中的错误乍看起来很奇怪,不论在1.3还是2.0中JsHelper都没有scriptBlock()这个方法啊。其实它的演变过程是这样的,2.0用JsHelper/HtmlHelper替换了JavascriptHelper,所以Upgrade插件就在视图中把$this->Javascript替换成了$this->Js,所以下面的代码:

<?php <span>$this</span>->Javascript->codeBlock(); ?>
    <span>//</span><span> 中间是JavaScript代码</span>
<?php <span>$this</span>->Javascript->blockEnd(); ?>

就变成了:

<?php <span>$this</span>->Js->codeBlock(); ?>
    <span>//</span><span> 中间是JavaScript代码</span>
<?php <span>$this</span>->Js->blockEnd(); ?>

这就是PHP代码中发生错误的原因。改正的方法,就是把上面的代码进一步改为:

<?php <span>$this</span>->Html->scriptStart(); ?>
    <span>//</span><span> 中间是JavaScript代码</span>
<?php <span>$this</span>->Html->scriptEnd(); ?>

这样就好了。

5.12 Undefined index: User

出问题的代码为:

<span>$user</span> = <span>$this</span>->Auth-><span>user();
</span><span>$this</span>->Soldier->id = <span>$user</span>['User']['id']; <span>//</span><span> error: Undefined index: User</span>

这是因为在2.0中,AuthComponent::user()的返回值发生了变化,只需做如下变化就可逢凶化吉、遇难成祥:

<span>$user</span> = <span>$this</span>->Auth-><span>user();
</span><span>$this</span>->Soldier->id = <span>$user</span>['id'];

5.13 如果用户登录时输入的用户名或者密码错误,没有提示

这个问题和前面的5.9 用户登录总是失败类似,都是因为在2.0中AuthComponent对用户登录时的验证发生了变化,需要进一步在修改上面的login()方法,在验证失败时显示错误提示,即为:

<span>//</span><span> 只是示意</span>
<span>public</span> <span>function</span><span> login() {
    </span><span>if</span> (!<span>$this</span>->request->is('post'<span>)) {
        </span><span>//</span><span> 显示登录表单</span>
    } <span>else</span><span> {
        </span><span>if</span> (<span>$this</span>->Auth->login()) { <span>//</span><span> 现在需要显示调用</span>
            <span>return</span> <span>$this</span>->redirect(<span>$this</span>->Auth-><span>redirectUrl());
        } </span><span>else</span><span> {
            </span><span>$this</span>->Session-><span>setFlash(
                </span>'账号或密码错误!',
                'default',
                <span>array</span>(),
                'auth'<span>
            );
        } 
    } 
}</span>

5.14 日期输入中,月份的下拉框中文翻译变成了英文

这个涉及i18n & l10n,即国际化与本地化(Internationalization & Localization),这其实有很多内容,但在这里不便展开讨论,更多的信息可见参考资料中的[10][11]。在2.0中,国际化与本地化也发生了一些变化,这里只简单解释一下这个问题中涉及的一些要点:

原来这个项目中1.3版本的代码使用的中文locale代码为cn,我没有去深究1.3中应当是什么。而2.0中这应当按照ISO 639-2规范为zho,这可以在lib\Cake\I18n\L10n.php中看到:

<span>class</span><span> L10n {
    </span><span>//</span><span> ...</span>

<span>/*</span><span>*
 * HTTP_ACCEPT_LANGUAGE catalog
 *
 * holds all information related to a language
 *
 * @var array
 </span><span>*/</span>
    <span>protected</span> <span>$_l10nCatalog</span> = <span>array</span><span>(
        </span><span>//</span><span> ...</span>
        'zh' => <span>array</span>('language' => 'Chinese', 'locale' => 'zho', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
        'zh-cn' => <span>array</span>('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'zho', 'charset' => 'GB2312', 'direction' => 'ltr'),
        'zh-hk' => <span>array</span>('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
        'zh-sg' => <span>array</span>('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
        'zh-tw' => <span>array</span>('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'),
        <span>//</span><span> ...</span>
<span>    );

    </span><span>//</span><span> ...</span>
}

FormHelper的日期方法在1.3就支持国际化与本地化,2.0也仍然支持,只是两个版本本地化翻译所在的domain(域)不同,这就导致所在的文件不同。详细解释如下。

在1.3中,我们可以查看cake\libs\view\helpers\form.php,在2140行左右,代码为:

<span>/*</span><span>*
 * Generates option lists for common <select /> menus
 * @access private
 </span><span>*/</span>
    <span>function</span> __generateOptions(<span>$name</span>, <span>$options</span> = <span>array</span><span>()) {
        </span><span>//</span><span> ...</span>
            <span>case</span> 'month':
                <span>if</span> (<span>$options</span>['monthNames'] === <span>true</span><span>) {
                    </span><span>$data</span>['01'] = __('January', <span>true</span><span>);
                    </span><span>$data</span>['02'] = __('February', <span>true</span><span>);
                    </span><span>$data</span>['03'] = __('March', <span>true</span><span>);
                    </span><span>$data</span>['04'] = __('April', <span>true</span><span>);
                    </span><span>$data</span>['05'] = __('May', <span>true</span><span>);
                    </span><span>$data</span>['06'] = __('June', <span>true</span><span>);
                    </span><span>$data</span>['07'] = __('July', <span>true</span><span>);
                    </span><span>$data</span>['08'] = __('August', <span>true</span><span>);
                    </span><span>$data</span>['09'] = __('September', <span>true</span><span>);
                    </span><span>$data</span>['10'] = __('October', <span>true</span><span>);
                    </span><span>$data</span>['11'] = __('November', <span>true</span><span>);
                    </span><span>$data</span>['12'] = __('December', <span>true</span><span>);
                } </span><span>else</span> <span>if</span> (<span>is_array</span>(<span>$options</span>['monthNames'])) {

这里没有指定域(domain),所以用的是缺省的域default。而且,在app\config\core.php的最后一行,指定了语言:

    Configure::write('Config.language', 'cn');

所以在1.3这个项目中月份的中文翻译位于app\locale\cn\LC_MESSAGES\default.po文件中。注意这个文件的路径是由多项因素组合确定的。

而在2.x中,在lib\Cake\View\Helper\FormHelper.php的2875行左右,我们可以看到:

<span>/*</span><span>*
 * Generates option lists for common <select /> menus
 *
 * @param string $name List type name.
 * @param array $options Options list.
 * @return array
 </span><span>*/</span>
    <span>protected</span> <span>function</span> _generateOptions(<span>$name</span>, <span>$options</span> = <span>array</span><span>()) {
        </span><span>//</span><span> ...</span>
            <span>case</span> 'month':
                <span>if</span> (<span>$options</span>['monthNames'] === <span>true</span><span>) {
                    </span><span>$data</span>['01'] = __d('cake', 'January'<span>);
                    </span><span>$data</span>['02'] = __d('cake', 'February'<span>);
                    </span><span>$data</span>['03'] = __d('cake', 'March'<span>);
                    </span><span>$data</span>['04'] = __d('cake', 'April'<span>);
                    </span><span>$data</span>['05'] = __d('cake', 'May'<span>);
                    </span><span>$data</span>['06'] = __d('cake', 'June'<span>);
                    </span><span>$data</span>['07'] = __d('cake', 'July'<span>);
                    </span><span>$data</span>['08'] = __d('cake', 'August'<span>);
                    </span><span>$data</span>['09'] = __d('cake', 'September'<span>);
                    </span><span>$data</span>['10'] = __d('cake', 'October'<span>);
                    </span><span>$data</span>['11'] = __d('cake', 'November'<span>);
                    </span><span>$data</span>['12'] = __d('cake', 'December'<span>);
                } </span><span>elseif</span> (<span>is_array</span>(<span>$options</span>['monthNames'])) {

这里指定了域cake。在2.x的代码中,我按照ISO 639-2规范把语言设置为:

<span>/*</span><span>*
 * Set the language for your application
 </span><span>*/</span>
<span>//</span><span> http://book.cakephp.org/2.0/en/core-libraries/internationalization-and-localization.html#localization-in-cakephp</span>
    Configure::write('Config.language', 'zho');

所以,在2.x中月份的中文翻译位于app\Locale\zho\LC_MESSAGES\cake.po。我们只需把1.3中的月份中文翻译搬到这个文件中即可:

<span># LANGUAGE translation of CakePHP Application
# Copyright YEAR NAME <EMAIL@ADDRESS>
#
msgid </span>""<span>
msgstr </span>""
"Project-Id-Version: zhandianr VERSION\n"
"POT-Creation-Date: 2014-07-26 23:04+0800\n"
"PO-Revision-Date: 2014-07-27 21:38+0800\n"
"Last-Translator: Zhu Ming <mingzhu.z@gmail.com>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"Language: zho\n"
"X-Generator: Poedit 1.6.7\n"
"X-Poedit-SourceCharset: UTF-8\n"<span>

msgid </span>"January"<span>
msgstr </span>"1月"<span>

msgid </span>"February"<span>
msgstr </span>"2月"<span>

msgid </span>"March"<span>
msgstr </span>"3月"<span>

msgid </span>"April"<span>
msgstr </span>"4月"<span>

msgid </span>"May"<span>
msgstr </span>"5月"<span>

msgid </span>"June"<span>
msgstr </span>"6月"<span>

msgid </span>"July"<span>
msgstr </span>"7月"<span>

msgid </span>"August"<span>
msgstr </span>"8月"<span>

msgid </span>"September"<span>
msgstr </span>"9月"<span>

msgid </span>"October"<span>
msgstr </span>"10月"<span>

msgid </span>"November"<span>
msgstr </span>"11月"<span>

msgid </span>"December"<span>
msgstr </span>"12月"

问题解决了。

5.15 模型(Model)的find方法返回值变化了

在1.3中,如果Model::find()没有读取到数据,那么返回值为false。而在2.x中,这种情况下返回值为空数组array()。所以,我把代码由原来的:

<span>$soldier</span> = <span>$this</span>->Solder->find('first', <span>array</span><span>(
    </span>'conditions' => <span>array</span>('id' => 267<span>)
));
</span><span>if</span> (<span>$soldier</span> !== <span>false</span><span>) {
  </span><span>//</span><span> 找到了</span>
} <span>else</span><span> {
  </span><span>//</span><span> 没找到</span>
}

改为:

<span>$soldier</span> = <span>$this</span>->Solder->find('first', <span>array</span><span>(
    </span>'conditions' => <span>array</span>('id' => 267<span>)
));
</span><span>if</span> (<span>count</span>(<span>$soldier</span>) !== 0<span>) {
  </span><span>//</span><span> 找到了</span>
} <span>else</span><span> {
  </span><span>//</span><span> 没找到</span>
}

即可。

至此,所有我在升级过程中遇到的与升级相关的问题,都讨论完毕了。

欢迎大家批评指正,留言讨论,互相切磋,共同提高。

A. 参考资料

魅族MX 213升级不25

已ROOT用户是不能在线升级的,请点击下载MX FLYME2.5固件,并同时勾选清除数据升级。www.meizu.com/...ype=mx
魅族企业平台 [官方认证]

怎使英雄无敌5 从13升级到最新版本

patch.ali213.net/view.asp?id=5003

魔法门之英雄无敌V资料片命运之锤(Heroes of Might And.Magic V Hammers of Fate)v2.1升级档免CD补丁

看看这个行不行吧
 

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn