當框架限制了我的想法,我選擇Hack


自框架出現以來,從來就不乏這方面的討論,比如《Java程序員的墮落》。一方面,框架大大簡化便利了開發;另一方面,又因框架做了太多的封裝,讓我們失去了很多深入的機會,或者一旦遇到一些莫名其妙的問題就容易陷入困境。

那么應不應該使用框架?我想這個問題不是個人所能回答的。更實際的問題是,如何利用好框架?

我的web學習經歷是最開始寫純粹html,接着css,不久接觸web標准,隨后學習js,然后不滿足於靜態頁而開始學習php。

學習php開始很長一段時間都是用的php內嵌sql再echo html(如果不是一開始就使用框架的話,這是學習php的必經之路了),往后開始做一些項目。開始是簡單的投票系統,接着是圖文直播系統、網絡課程,到現在的教室安排系統。規模從小到大、由簡單到復雜,在這個過程中,我開始意識到,原始的php開發模式已經無法適應大量而復雜的項目了。如果不采取一些措施對代碼進行有效的組織,那么光是解決一些簡單而又重復的問題就可以把人累死。

借此開始接觸MVC,並按照自己的理解形成了一套面向過程的MVC。有了一個簡單的框架,開發變得有序多了,而且具有很好的擴展性。

回顧php的框架史,早在php具備面向對象特性之前就出現了各種框架,但並不形成氣候,大多人還是寧願使用自己的框架。直到php具備了面向對象特性,各種框架才如雨后春筍般誕生並形成了不同規模的社區。這里有個事實,面向對象的MVC框架局限性太大。就我個人來說,自己的那套面向對象MVC框架只是簡單的分層而已,很多重復的工作並沒有得到簡化。

那么我要自己實現一個面向對象的MVC框架么,面對現在這么多php框架,為什么還要自己實現呢?

即使不是自己實現,面對現在數量如此之多的php框架還是很令人頭疼的,不過想想實在沒有必要過多的糾結,我本來就沒打算今后只使用一個php框架,作為入門和學習我選擇了ThinkPHP。

回到最初的問題,如何利用好框架,在我看來,我們應該擁抱框架(當然,根據實際情況,也有不用框架的時候),利用框架加快開發和方便維護才是實際的,但與此同時我們也要做好Hack框架的准備,有時為了突破框架的限制,我們需要采取一些特別的手段甚至改寫框架源代碼(這也是開源的意義不是么)。

突破ThinkPHP關系模型單層限制

最近開始使用ThinkPHP開發項目,但在使用的過程中遇到了一個小問題,ThinkPHP的關系模型只支持一層關系,這個問題其他人也發現並提出了

遞歸的關系模型是很有價值的,並且項目中確實要用到,然而官方的RelationModel沒有考慮到這點。

最壞的打算是改寫ThinkPHP/Extend/Model/RelationModel.class.php,使其可以遞歸的處理多層關系。但閱讀RelationModel的實現代碼后想到,只要繼承原RelationModel,並重寫查詢方法,對每個查詢語句添加relation(true),這樣通過原RelationModel,新的RelationModel就可以遞歸的處理多層關系了。

這是原RelationModel的源代碼:


class RelationModel extends Model {
	protected function getRelation(&$result,$name='',$return=false) {
		$model = D($mappingClass);
		switch($mappingType) {
			case HAS_ONE:
				$pk   =  $result[$mappingKey];
				$mappingCondition .= " AND {$mappingFk}='{$pk}'";
				$relationData   =  $model->where($mappingCondition)->field($mappingFields)->find();
				break;

我的解決是新建一個_ReletionModel,繼承自RelationModel,重寫getRelation方法:


class _RelationModel extends RelationModel {
    protected function getRelation(&$result,$name='',$return=false) {
		$model = D($mappingClass);
		switch($mappingType) {
			case HAS_ONE:
				$pk   =  $result[$mappingKey];
				$mappingCondition .= " AND {$mappingFk}='{$pk}'";
				$relationData   =  $model->relation(true)->where($mappingCondition)->field($mappingFields)->find();
				break;

使用新的_RelationModel創建出來的數據模型就可以遞歸處理多層關系了。

Bootstrap的modal無法實現不同remote的適配器

在我的項目中有一個表格,我希望通過bootstrap的modal ajax獲取<a>標簽href所指向的頁面,簡單的做法是使用bootstrap提供的DOM API,每個<a>標簽的data-target指向同一個modal元素(所謂的適配器模式),這樣避免了大量的js代碼,卻不想引入了新問題。

我遇到的問題可以簡單用以下代碼描述:


<a id="a" data-target="#modal">a</a>
<a id="b" data-target="#modal">b</a>
<div id="modal" class="modal hide fade">
	<div class="modal-header">
		<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
		<h3>Title</h3>
	</div>
	<div class="modal-body"></div>
	<div class="modal-footer">
		<button class="btn" data-dismiss="modal" aria-hidden="true">關閉</button>
	</div>
</div>

當點擊a鏈接,彈出的是a所指向的頁面,但點擊b鏈接還是彈出a所指向頁面,這顯然不是我想要的。

嘗試過多種方法無果后,最后決定從bootstrap.js源代碼下手。


 /* MODAL PLUGIN DEFINITION
  * ======================= */

  $.fn.modal = function (option) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('modal')
        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
      if (!data) $this.data('modal', (data = new Modal(this, options)))
      if (typeof option == 'string') data[option]()
      else if (options.show) data.show()
    })
  }

 /* MODAL DATA-API
  * ============== */

  $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
    var $this = $(this)
      , href = $this.attr('href')
      , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
      , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())

    e.preventDefault()

    $target
      .modal(option)
      .one('hide', function () {
        $this.focus()
      })
  })

可以看到,bootstraup的modal通過jquery的data方法存儲實例化的modal對象,下次調用會判斷是否已經實例化,如果已實例化,則使用已實例化的對象。

現在我需要對於不同的href重新實例化,顯然,只要添加一個判斷條件即可


……
if(!data || (options.remote && data.options.remote != options.remote)) $this.data('modal', (data = new Modal(this, options)))
……
, option = $target.data('modal') && $target.data('modal').href == href ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM