当框架限制了我的想法,我选择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())
……
posted @ 2013-02-11 15:08  7c00  阅读(3304)  评论(7编辑  收藏  举报