摘要:最近把一個CakePHP 1.3的項目升級到了2.x,當然就用最新的版本2.5.3了,結果基本滿意。本文記錄了升級的過程,包括使用的工具,遇到的問題和相應的解決方法。
這篇文章涉及的內容要求至少有CakePHP中級水平,如果你是剛開始使用CakePHP,建議先不要作這樣的嘗試,否則遇到問題都不知道怎麼解決。
1. 為什麼要升級
2. 項目概況
3. 使用的工具
4. 升級的過程
5. 升級之後遇到的問題及解決方法
A. 參考資料
升級到最新版本有很多好處,可以得到最新的更新和功能,可以使用DebugKit這樣的調試工具,可以使用View Block方便地把CSS和JavaScript放在頁面中你希望的地方,而不再痛苦地受限於舊的方式,等等。View Block一直是我最希望使用的特性。
這個項目的開發大致起始於2012年底,我從2013年中開始參與,到2014年中,所有用戶要求的功能基本都完成了。我參與了大概1年左右,只是利用業余時間進行。代碼一開始是抄自於一個CakePHP 1.3的項目,而沒有使用當時最新的2.x版本,這也使得許多開發工作不能利用框架最新的特性和工具,延長了開發周期。可以說,這個項目從開始就做了錯誤的選擇。先後參與的開發人員前後有6個人之多,多數是臨時抓來的,大部分人做一段時間之後就會離開,有些功能甚至沒有完成就走人了。而且大家對CakePHP這個框架沒有深入的了解,導致這個項目的代碼沒有一致性,也缺乏統一的計劃、架構和規范,沒有單元測試。總之,項目的代碼質量是不能令人滿意的。這些恐怕是大部分業余項目難以避免的問題。
幸好,這個項目不算特別復雜,計有:
通過這些數據可以看出這個項目的規模,應該說是個中小型網站吧。
升級只使用了2個工具,首先是官方的Upgrade Shell,以及DerEuroMark的Upgrade Plugin。
真正動手升級之前我花了一些時間閱讀參考資料中列出的文檔,實際的升級過程前後總共花了4天時間,不過這裡面相當一部分時間用於升級後的測試、以及尋找解決問題的方法。我畢竟從1年前才開始真正使用PHP和CakePHP來開發實際使用的網站,而且只是利用業余時間,所以時間有限,很多東西也都是邊做邊摸索學習,主要目標是要完成用戶需求所要求的功能,來不及了解CakePHP框架的各個方面。如果你有相應的經驗,或者有解決下面所涉及問題的這些知識,這個過程會快許多。
首先,確保升級之前,應用程序運行良好,做好代碼和數據的備份。如果沒有備份,請就此打住!!!
我使用Git(TortoiseGit)做源碼控制,這讓我可以隨時回到過去某一個時間點。數據庫使用的是MySQL,升級之前也要做好備份。如果升級過程出了問題,進行不下去,備份讓你可以恢復到開始升級之前的狀態;如果沒有備份,那你可就進退維谷了。
這個項目在升級前的目錄結構,如下圖所示,
圖中,cake為CakePHP 1.3的核心庫,app是應用程序代碼。
下載最新的CakePHP,我用的是2.5.3,打開壓縮包,如下圖所示。
圖中的lib目錄就是CakePHP的核心庫,把這個lib目錄拷貝到根目錄下,然後刪除1.3的cake目錄,得到如下圖所示的目錄結構。
圖中的lib\Cake目錄就是CakePHP 2.x的核心庫。
Upgrade Shell是CakePHP核心的一部分,位於lib\Cake\Console\目錄下,只需確保能夠運行CakePHP Console可執行文件就可以了,這可以參考CakePHP Console的文檔。如下圖所示,
圖中的cake是*nix下的可執行文件,cake.bat是Windows下的可執行文件。我采用的做法,是參考了Upgrade Shell的文檔,把lib\Cake\Console\目錄拷貝到app目錄下,這樣只是執行的命令行路徑有所不同,結果是一樣的,如下圖所示。
圖中的app\Console\就是我采用的Console路徑。
下載DerEuroMark的Upgrade Plugin,解壓之後拷貝到app\Plugin\目錄下,如下圖所示。
按照Upgrade Shell的文檔,可以運行.\Console\cake Upgrade.Upgrade all,這會執行所有的升級任務;當然也可以逐個執行單個任務。因為這是官方的工具,我就所有的任務一起運行了。
我的操作系統是Windows 7,在命令行下進入app\目錄,然後運行.\Console\cake upgrade all,結果如下:
D:\...\app>.\Console\cake upgrade all Welcome to CakePHP v2.5.3 Console --------------------------------------------------------------- App : app Path: D:\...\app\ --------------------------------------------------------------- Running tests Running locations Upgrading locations for plugin contact_us Upgrading locations for plugin file_upload Moving View\handler to View\Handler Moving View\helpers to View\Helpers Moving View\layouts to View\Layouts Upgrading locations for plugin popup Moving View\elements to View\Elements Moving View\helpers to View\Helpers Upgrading locations for app directory Moving config to Config Moving Config\schema to Config\Schema Moving View\contacts to View\Contacts Moving View\elements to View\Elements Moving View\errors to View\Errors Moving View\group to View\Group Moving View\help to View\Help ... ... ... ... Running components Done updating D:\...\app\Controller\Component\CropComponent.php Running exceptions Done updating D:\...\app\Controller\AppController.php
Done updating D:\...\app\Controller\CommentController.php
Done updating D:\...\app\Controller\ContactsController.php
Done updating D:\...\app\Controller\DataConversionController.php
Done updating D:\...\app\Controller\GroupPostController.php
Done updating D:\...\app\Controller\GroupTalkController.php
Done updating D:\...\app\Controller\HelpController.php
... ...
注:這裡看到的\...\是我省略了真實路徑。
注:這個結果有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了。
雖然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.Upgrade locations Welcome to CakePHP v2.5.3 Console --------------------------------------------------------------- App : app Path: D:\...\app\ --------------------------------------------------------------- Moving locale to Locale Moving config to Config Moving Config\schema to Config\Schema Moving View\contacts to View\Contacts Moving View\elements to View\Elements Moving View\errors to View\Errors Moving View\group to View\Group Moving View\help to View\Help Moving View\helpers to View\Helpers Moving View\index to View\Index Moving View\job to View\Job Moving View\layouts to View\Layouts Moving View\messages to View\Messages Moving View\news to View\News Moving View\os to View\Os Moving View\pages to View\Pages Moving View\scaffolds to View\Scaffolds Moving View\uc to View\Uc Moving View\users to View\Users Moving View\video to View\Video Removing empty folder \controllers
我又繼續運行了其它命令,所有命令如下面列表所示。注意,有些升級任務沒有引起任何變化,故記錄為no change。
[x] .\Console\cake Upgrade.Upgrade locations
[x] .\Console\cake Upgrade.Upgrade webroot
[x] .\Console\cake Upgrade.Upgrade routes
[x] .\Console\cake Upgrade.Upgrade database
[x] .\Console\cake Upgrade.Upgrade basics
[x] .\Console\cake Upgrade.Upgrade helpers: no change
[x] .\Console\cake Upgrade.Upgrade request
[x] .\Console\cake Upgrade.Upgrade configure: no change
[x] .\Console\cake Upgrade.Upgrade constants: no change
[x] .\Console\cake Upgrade.Upgrade controllers
[x] .\Console\cake Upgrade.Upgrade components: no change
[x] .\Console\cake Upgrade.Upgrade exceptions: no change
[x] .\Console\cake Upgrade.Upgrade views
[x] .\Console\cake Upgrade.Upgrade stylesheets
[x] .\Console\cake Upgrade.Upgrade legacy
[x] .\Console\cake Upgrade.Upgrade constructors: no change
[x] .\Console\cake Upgrade.Upgrade paginator: no change
[x] .\Console\cake Upgrade.Upgrade name_attribute
[x] .\Console\cake Upgrade.Upgrade methods
[x] .\Console\cake Upgrade.Upgrade cake13: no change
[x] .\Console\cake Upgrade.Upgrade cake20: no change
[x] .\Console\cake Upgrade.Upgrade cake21
[x] .\Console\cake Upgrade.Upgrade cake23
[x] .\Console\cake Upgrade.Upgrade cake24: no change
[x] .\Console\cake Upgrade.Upgrade cake25
[x] .\Console\cake Upgrade.Upgrade validation: no change
[x] .\Console\cake Upgrade.Upgrade estrict: no change
[x] .\Console\cake Upgrade.Correct stable
[x] .\Console\cake Upgrade.Convert arrays -v
應當注意的是,在運行每個命令之前,最好還是讀一下源代碼,知道每個升級任務做的是什麼改變。比如最後一個命令cake Upgrade.Convert arrays -v,這個升級任務把數組由下面的長格式:
array('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,這樣就提高了對運行環境的要求,縮小了代碼的適用范圍,如果將來遇到遷移服務器的情況,在選擇運行環境時,就會少了很多選擇,也可能意味著不得不付出更高的服務器空間租用費用。所以,建議這個升級任務,除非有必要,不要執行。
到此,所有升級工具能做的事情都已經做了。似乎升級大業已經完成了,後來才知道,這才進行了不到一半,真是行百裡者半九十。
該試著運行一下應用程序了。當我打開首頁的時候,我驚呆了,白屏!壞了!由Firebug知道服務器返回的是錯誤500,這意味著服務器錯誤,但仍然不知道服務器上哪裡出問題了,當時真有些不知所措,這已經是晚上11點多了,在QQ群裡問了一圈,也不得要領。試了各種調試方法,PHP的錯誤日志,CakePHP的日志,都沒有任何記錄。這一晚沒睡好!
第二天,經過文檔的閱讀以及很多思考,我想到,升級工具已經幫我做了很多事情,但仍然有些部分是升級工具沒有做的,這恐怕要我自己手工做了,畢竟工具不是萬能的,還有不少事非得自己動手不可。
我先著手的是下面這些配置文件:
app\Config\bootstrap.php app\Config\core.php
我逐個配置比較1.3和2.x的兩個版本,一些配置取消了,一些配置是新增的。改了個七七八八,但仍然是白屏,不過這項工作並不是沒用的,這畢竟還是必不可少的。
我再按照更改目錄名稱的小竅門,改了不少git庫中的目錄名大小寫,不過我也知道這對於白屏沒有幫助,因為git庫不會直接影響程序運行結果。不過這仍然是保證git庫一致性必須的工作。
最終,我想到了應用程序的入口,index.php。整個目錄結構中總共有3個index.php:
index.php app\index.php app\webroot\index.php
比較1.3和2.x的版本,其中,根目錄下的index.php和app\webroot\index.php有實質性的變化,另外一個app\index.php只是注釋的變化。
改完3個index.php後,首頁總算是能夠顯示了,只是還是很不正常,但CakePHP的日志也有了,這樣就可以通過日志准確定位錯誤發生的位置了。
下面要對付的錯誤在CakePHP的日志error.log中是這樣記錄的:
2014-07-23 17:44:01 Error: [MissingPluginException] Plugin Popup could not be found. Exception Attributes: array ( 'plugin' => 'Popup', ) Request URL: /
Stack Trace:
後面還有更詳細的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的要求了。
下一個錯誤:
Fatal Error (1): Unsupported operand types in [...\html\lib\Cake\View\Helper\FormHelper.php, line 2477]
這一行代碼位於FormHelper::dateTime()方法。這個錯誤是由於從1.3到2.5,FormHelper的一些方法去掉了$select參數,這正包括FormHelper::dateTime(),其原型從:
FormHelper::dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $selected = null, $attributes = array())
變成了:
FormHelper::dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $attributes = array())
我對應用程序的代碼做的相應變化就是,從:
echo $this->Form->dateTime('Voucher.expired', 'YMD', '24', strtotime('+15 day'), array(
'label' => false,
'minYear' => date('Y'),
'maxYear' => date('Y') + 1,
'empty' => false
));
改成:
echo $this->Form->dateTime('Voucher.expired', 'YMD', '24', array(
'selected' => strtotime('+15 day'),
'label' => false,
'minYear' => date('Y'),
'maxYear' => date('Y') + 1,
'empty' => false
));
這個錯誤如下:
Error: [MissingComponentException] Component class UploadFileComponent could not be found.
原因在於,從2.0開始,所有的組件都必須繼承自Component基類,而在1.3中沒有這個要求。
這個錯誤是:
Error: Fatal Error (1): Cannot use object of type ComponentCollection as array in [...\app\Plugin\FileUpload\Controller\Component\UploadFileComponent.php, line 61]
原因是Component的構造函數也發生了變化,在1.3中,是:
function __construct($options = null) { }
而在2.x中,這變成了:
function __construct(ComponentCollection $collection, $options = null ) { }
這是因為,從2.0開始,控制器(Controller)不再直接連接控件(Component),而是通過ComponentCollection(即Controller::$Components)來操縱它的控件,詳見2.0 Migration Guide中的Controller一節。
請對所有控件(Component)的構造函數做相應的修改。
錯誤信息為:
Notice (8): Indirect modification of overloaded property PostsController::$paginate has no effect [APP/Controller/PostsController.php, line 13
這個錯誤的解釋見DerEuroMark博客中“Indirect modification” for pagination一節。較好的做法是采用2.0的語法,不過我匆匆閱讀了文檔,仍然沒有搞明白2.0的語法的含義,就采用了文中提到的簡便方法:
class AppController extends Controller { //... /** * The paginate options for this controller * * @var array */ // TODO: upgrade to the new PaginatorComponent syntax public $paginate = array(); //... }
這就足夠消除這個問題提示,並讓應用程序正常運行。而我在注釋中留下TODO標簽,等以後有時間再來改進。我需要盡可能縮短升級所用的時間,因為有可能項目中別的開發者也正在做其他的改動,我升級所花的時間越多,這期間別人做的改動就可能越多,合並的時候發生矛盾的機會就越多。
這個錯誤的日志為:
Error: [MissingHelperException] Helper class JavascriptHelper could not be found. Exception Attributes: array ( 'class' => 'JavascriptHelper', 'plugin' => false, )
2.0中,JavascriptHelper已作廢,而由JsHelper和HtmlHelper代替,詳見2.0 Migration Guide中的XmlHelper, AjaxHelper and JavascriptHelper removed一節。所以,我要做的是,在相應的控制器中用JsHelper代替JavascriptHelper,把:
public $helpers = array( //... ,'Javascript' );
改為:
public $helpers = array( //... ,'Js' => array('Jquery') );
錯誤信息:
Error: Fatal Error (64): Cannot use isset() on the result of a function call (you can use "null !== func()" instead) in [D:\...\app\Controller\SoldiersController.php, line 175]
引起錯誤的代碼為:
if (isset($this->request->query('email'))) { }
改為:
if (null !== $this->request->query('email')) { }
這是因為在2.0中,AuthComponent驗證用戶的方式略有變化,用戶代碼需要顯示調用AuthComponent::login()來驗證用戶登錄信息。原來的代碼:
// 只是示意 public function login() { if (!$this->request->is('post')) { // 顯示登錄表單 } else { // 登錄成功 } }
需要變成:
// 只是示意
public function login() {
if (!$this->request->is('post')) {
// 顯示登錄表單
} else {
if ($this->Auth->login()) { // 現在需要顯示調用
return $this->redirect($this->Auth->redirectUrl());
}
}
}
這是由於在CakePHP 2.0中,廢止了對PHP 4的支持,所有的類成員都可以用public、protected和private來聲明。Upgrade插件要把視圖(View)中的JavaScript變量誤當做PHP類成員,而改變了聲明,導致了浏覽器中JavaScript的錯誤,這可以從Firebug中看到,如下圖所示。
錯誤的代碼為:
<?php $this->Html->scriptStart(['inline' => false]); ?> $(document).ready(function() { // ... public $that = $(this); // ... }); <?php $this->Html->scriptEnd(); ?>
很容易地改正為:
<?php $this->Html->scriptStart(['inline' => false]); ?> $(document).ready(function() { // ... var $that = $(this); // ... }); <?php $this->Html->scriptEnd(); ?>
這個發生在視圖(View)中的錯誤乍看起來很奇怪,不論在1.3還是2.0中JsHelper都沒有scriptBlock()這個方法啊。其實它的演變過程是這樣的,2.0用JsHelper/HtmlHelper替換了JavascriptHelper,所以Upgrade插件就在視圖中把$this->Javascript替換成了$this->Js,所以下面的代碼:
<?php $this->Javascript->codeBlock(); ?> // 中間是JavaScript代碼 <?php $this->Javascript->blockEnd(); ?>
就變成了:
<?php $this->Js->codeBlock(); ?> // 中間是JavaScript代碼 <?php $this->Js->blockEnd(); ?>
這就是PHP代碼中發生錯誤的原因。改正的方法,就是把上面的代碼進一步改為:
<?php $this->Html->scriptStart(); ?> // 中間是JavaScript代碼 <?php $this->Html->scriptEnd(); ?>
這樣就好了。
出問題的代碼為:
$user = $this->Auth->user(); $this->Soldier->id = $user['User']['id']; // error: Undefined index: User
這是因為在2.0中,AuthComponent::user()的返回值發生了變化,只需做如下變化就可逢凶化吉、遇難成祥:
$user = $this->Auth->user(); $this->Soldier->id = $user['id'];
這個問題和前面的5.9 用戶登錄總是失敗類似,都是因為在2.0中AuthComponent對用戶登錄時的驗證發生了變化,需要進一步在修改上面的login()方法,在驗證失敗時顯示錯誤提示,即為:
// 只是示意 public function login() { if (!$this->request->is('post')) { // 顯示登錄表單 } else { if ($this->Auth->login()) { // 現在需要顯示調用 return $this->redirect($this->Auth->redirectUrl()); } else { $this->Session->setFlash( '賬號或密碼錯誤!', 'default', array(), 'auth' ); } } }
這個涉及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中看到:
class L10n { // ... /** * HTTP_ACCEPT_LANGUAGE catalog * * holds all information related to a language * * @var array */ protected $_l10nCatalog = array( // ... 'zh' => array('language' => 'Chinese', 'locale' => 'zho', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'zho', 'charset' => 'GB2312', 'direction' => 'ltr'), 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'), 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'zho', 'charset' => 'utf-8', 'direction' => 'ltr'), // ... ); // ... }
FormHelper的日期方法在1.3就支持國際化與本地化,2.0也仍然支持,只是兩個版本本地化翻譯所在的domain(域)不同,這就導致所在的文件不同。詳細解釋如下。
在1.3中,我們可以查看cake\libs\view\helpers\form.php,在2140行左右,代碼為:
/** * Generates option lists for common <select /> menus * @access private */ function __generateOptions($name, $options = array()) { // ... case 'month': if ($options['monthNames'] === true) { $data['01'] = __('January', true); $data['02'] = __('February', true); $data['03'] = __('March', true); $data['04'] = __('April', true); $data['05'] = __('May', true); $data['06'] = __('June', true); $data['07'] = __('July', true); $data['08'] = __('August', true); $data['09'] = __('September', true); $data['10'] = __('October', true); $data['11'] = __('November', true); $data['12'] = __('December', true); } else if (is_array($options['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行左右,我們可以看到:
/** * Generates option lists for common <select /> menus * * @param string $name List type name. * @param array $options Options list. * @return array */ protected function _generateOptions($name, $options = array()) { // ... case 'month': if ($options['monthNames'] === true) { $data['01'] = __d('cake', 'January'); $data['02'] = __d('cake', 'February'); $data['03'] = __d('cake', 'March'); $data['04'] = __d('cake', 'April'); $data['05'] = __d('cake', 'May'); $data['06'] = __d('cake', 'June'); $data['07'] = __d('cake', 'July'); $data['08'] = __d('cake', 'August'); $data['09'] = __d('cake', 'September'); $data['10'] = __d('cake', 'October'); $data['11'] = __d('cake', 'November'); $data['12'] = __d('cake', 'December'); } elseif (is_array($options['monthNames'])) {
這裡指定了域cake。在2.x的代碼中,我按照ISO 639-2規范把語言設置為:
/** * Set the language for your application */ // http://book.cakephp.org/2.0/en/core-libraries/internationalization-and-localization.html#localization-in-cakephp Configure::write('Config.language', 'zho');
所以,在2.x中月份的中文翻譯位於app\Locale\zho\LC_MESSAGES\cake.po。我們只需把1.3中的月份中文翻譯搬到這個文件中即可:
# LANGUAGE translation of CakePHP Application # Copyright YEAR NAME <EMAIL@ADDRESS> # msgid "" msgstr "" "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 <[email protected]>\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" msgid "January" msgstr "1月" msgid "February" msgstr "2月" msgid "March" msgstr "3月" msgid "April" msgstr "4月" msgid "May" msgstr "5月" msgid "June" msgstr "6月" msgid "July" msgstr "7月" msgid "August" msgstr "8月" msgid "September" msgstr "9月" msgid "October" msgstr "10月" msgid "November" msgstr "11月" msgid "December" msgstr "12月"
問題解決了。
在1.3中,如果Model::find()沒有讀取到數據,那麼返回值為false。而在2.x中,這種情況下返回值為空數組array()。所以,我把代碼由原來的:
$soldier = $this->Solder->find('first', array( 'conditions' => array('id' => 267) )); if ($soldier !== false) { // 找到了 } else { // 沒找到 }
改為:
$soldier = $this->Solder->find('first', array( 'conditions' => array('id' => 267) )); if (count($soldier) !== 0) { // 找到了 } else { // 沒找到 }
即可。
至此,所有我在升級過程中遇到的與升級相關的問題,都討論完畢了。
歡迎大家批評指正,留言討論,互相切磋,共同提高。
已ROOT用戶是不能在線升級的,請點擊下載MX FLYME2.5固件,並同時勾選清除數據升級。www.meizu.com/...ype=mx
魅族企業平台
[官方認證]
patch.ali213.net/view.asp?id=5003
魔法門之英雄無敵V資料片命運之錘(Heroes of Might And.Magic V Hammers of Fate)v2.1升級檔免CD補丁
看看這個行不行吧