注:這裡的“無侵入”是指不修改cake的核心源碼的方式來實現功能擴展。
Why?
Cake 內置不少方便的view helper,如其中的TextHelper,有個truncate方法,用來實現常見的“簡介”文字修剪,但在實際使用中發現對中文支持不好,因為它是按字節剪切的,會有把末尾單個中文字剪掉一半的情況發生,而且已經在多處的vIEw中使用了,要替換成其他helper方法也不爽,最好的辦法就是能從內部“修復”這個方法。
How?
思路跟擴展Component類似:在載入helpers定義時載入自定義的、已擴展過的helper即可。
helpers用於輔助view,自然由view來載入並初始化,在cake/libs/view/vIEw.PHP 找到核心VIEw class,其 _loadHelpers 方法顧名思義就是用來干這活的。
要怎樣覆蓋此行為?詳見
1.修改默認的View為自定義的AppVIEw:
// @app/app_controller.PHP
class AppController extends Controller {
var $vIEw = 'app';
2 繼承出一個AppView,覆蓋_loadHelpers 方法: // @app/vIEws/app.PHP
class AppView extends VIEw * override parent method for enable loading extended helpers by RainChen @ 2008-5-14 15:00
* Loads helpers, with their dependencIEs. * @param array $loaded List of helpers that are already loaded.
* @param array $helpers List of helpers to load.
* @param string $parent holds name of helper, if loaded helper has helpers
* @return array function &_loadHelpers(&$loaded, $helpers, $parent = null) $loaded = parent::_loadHelpers($loaded, $helpers, $parent);
foreach(array_keys($loaded) as $helper) //hack by RainChen
//@ 2008-5-14 15:28
//@ load extended helpers
//@ link http://debuggable.com/posts/best-practises-bug-fixing-without-core-hacking:480f4dd5-57fc-4389-8948-49f6cbdd56cb
if(preg_match('|(.+)Ext$|', $helper, $matches) && $matches[1] && !isset($loaded[$matches[1]])) // only work with core helpers
if(is_file(CAKE_CORE_INCLUDE_PATH.DS.'cake'.DS.'libs'.DS.'vIEw'.DS.'helpers'.DS.low($matches[1]).'.PHP')) $loaded[$matches[1]] = &$loaded[$helper]; }
//hack end return $loaded; }
3. 添加擴展版的TextExtHelper (保存為app/vIEws/helpers/text_ext.PHP):
<?PHP * extend Cake Texthelper App::import('Helper', 'Text');
class TextExtHelper extends TextHelper function hi() return 'Cake'; }
?>
4. 在原本要使用TextHelper的controller聲明改為:
var $helpers = array('TextExt');5. 測試:在vIEw裡寫入 <?= $text->hi() ?>,會顯示Cake,表示已經成功注入TextHelper中了。
6. 修正 truncate 方法(最簡單適用原則):
// overrid parent method for fixing enconding problem
function truncate($text, $length = 100, $ending = '...', $exact = true, $considerHtml = false) $truncate = parent::truncate($text, $length, $ending, $exact, $considerHtml);
if(!$considerHtml) if($ending != '' && function_exists('mb_convert_encoding')) $encoding = mb_detect_encoding($text, 'GBK, UTF-8, ASCII');
$truncate = substr($truncate, 0, -strlen($ending));
$truncate = mb_convert_encoding($truncate, $encoding, $encoding);
$truncate .= $ending; }
return $truncate;
}