`

ThinkPHP最佳实践——自己的一点体会

    博客分类:
  • php
阅读更多

更多是写给刚接触thinkphp的菜鸟看的,呵呵,自己还不敢自居***

 

主要分以下几个部分,以1.5版本为例

 

文件组织结构 ——都知道tp比较rails,也比较java framework。从官方给出的例子和文档,我隐约总结了以下几点

 

1.COC,现在在框架流行这个,约定大于配置(编程)。核心包在ThinkPHP文件夹中,围绕lib/ThinkPHP/Core,主要把结构分成了Action Model两层。具体涉及到很多,主要就是插件扩展和结合第三方库(类/函数),主要关系到Vendor/Lib/Common三个目录,文档上有详细介绍,需要注意的是命名,比如Lib下一般Org/Com开头,详细见源码import方法。

 

2.App和ThinkPHP。tp的mvc采用的单入口,前端控制器+路由形式,一个单独的应用主要的代码组织结构就是

围绕Tp两层 + Tp扩展基础库(Date/Image)等 + 第三方库

 

其中一个官方推荐是——高于应用的全局Public文件夹(主要是view层相关),一样全局的(放Tp下)和局部的(放App Common or Lib下)

 

PS:推荐/Public/AppName/Css(Js Images)的形式,在view层用__PUBLIC__/**

         或者/AppName/Common(Web)/Css(Js Images)的形式,在view层用__WEB__/**,通过修改源码ThinkTemplate parse方法加入自己的view常量。

 

推荐第三方*** ——几个很好用的东东,虽然有的部分和php自带或tp自己实现的重叠

1.phpmailer

2.securimage

3.model-pagination(我自己又实现了一种)

4.httpdownload

 

--no-php--(view tier refer)

5.blueprint

6.jquery + plugin

7.kindeditor/fckeditor

 

Mvc中Action(Command)的OOD ——从java***的一些汲取的,比如filter\chain\strategy,本身前端控制器到Command处理对象,就是一种Strategy Design Pattern。出发点贯彻了php的简介性,无interface abstract class,只需要extends Action就可以了。所以很多时候你可以来个BaseAction来处理一些常用的逻辑,比如

log

session check

access filter / tracker

error display / redirect

http header set

common libs import / requre

common page variables assign

 

推荐为abstract

 

Mvc中View Tier的Tiles ——Tiles无非就是重用的目的,如何尽量重复使用html代码组成各种不用的page,这点每个人都有自己的体会,我只是就自己的一点经历,随便说点,欢迎大家拍砖和纠正

 

1.page divide + include这个想必大家都在用,比如化分出来一个 html_head,html_main_nav / sidebar,html_main_content,html_foot等,关键为非就是每一快的动态变量的设计,

 

比如<meta>标签里的作者信息、copyright等,

<head>标签里的js css等

navigation bar的list和current css区别等

 

PS:我主要使用tp自带的template,但我想smarty common-template discuz-template等其他的都差不多吧,正如jsp-tiles、sitemesh-tiles、freemarker macro差不多一样。

注意一点,php整个页面无论如何divide include,使用的多是全局变量,这点和java中的模板引擎不同。

 

2.tp自带的template有几个标签很好用,因为最初设计时候,就是多皮肤(style)的支持,有@ :等符号可以便捷动态寻找加载不同皮肤(默认default文件夹)下不同模块下的文件。

 

PS:修改included文件后,记得要clear View Cache

 

WebUI、Web flow、Access Control等功能的自定义扩展 ——

Tp自己有个rbac实现,我只是看看源码,到没有用过,不多说。我有两个实现方式,一个对于简单的,通过配置和Action控制,基本Session验证,自定义TagLib实现基本的Url/Page级别的验证。一个复杂点的,模型建立在数据库段,抽象可访问资源,通过php简洁优秀的反射机制实现粒度到业务逻辑方法级别的权限控制。

 

WebUI一般框架都不会自己费力去实现一个的,不是很多lib都可选么,不错,比如Extjs Jquery UI等,grails自带一个基于prototype+***。我业余时间收集了一些jquery相关的,大概40个常用的plugin,并用java的freemarker实现了一些基本的web ui组件,加上blueprint等css框架,web代码写起来都特别简单并且相似。下面是一些源码

 

<#-- JQuery and JQuery plugins -->

<#assign beginPath="/swsj/zftl/" />

<#assign default_js_list=['']>
<#assign default_css_list=['normal.css', 'widget.css']>

<#assign default_include_feature_list=[
	'common_css',
	'cookie',
	'drag',
	'nice_form', 
	'hot_key', 
	'layout', 
	'mask',
	'tip',
	'validate',
	'weebox']>

<#assign refer_widget_list=[
	'accordion',
	'chart',
	'color_picker',
	'count_down',
	'date_picker',
	'dock',
	'editor',
	'grid',
	'light_box',
	'linked_select',
	'menu',
	'messager',
	'multiple_select',
	'panel',
	'process_bar',
	'rater',
	'scroll',
	'shuffle',
	'slider',
	'status_bar',
	'tab',
	'time_picker',
	'timer',
	'tree',
	'window'
	]>

<#-- html head, js/css refer -->
<#macro html_head widget_list=['all']>
<script type="text/javascript" src="${beginPath}js/jquery1.2.6.js"></script>


<script type="text/javascript" src="${beginPath}js/bgiframe.js"></script>
<script type="text/javascript" src="${beginPath}js/chili.pack.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.cookie.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.dimensions.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.easing.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.metadata.js"></script>

<script type="text/javascript" src="${beginPath}js/jquery.jNice.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.hotkeys.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.maskedinput.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.tooltip.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.validate.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.weebox.js"></script>

<link href="${beginPath}css/weebox.css" rel="stylesheet" type="text/css" />
<link href="${beginPath}css/jquery.tooltip.css" rel="stylesheet" type="text/css" />

<#list widget_list as widget_refer>

<#if widget_refer == 'all' || widget_refer == 'blueprint'>
<!-- Blue Print Css Framework -->
<link href="${beginPath}css/blueprint/blueprint/screen.css" rel="stylesheet" type="text/css" />
<!--[if IE]><link rel="stylesheet" href="${beginPath}/css/blueprint/blueprint/lib/ie.css" type="text/css" media="screen, projection"><![endif]-->
<!-- Import plugins -->
<link rel="stylesheet" href="${beginPath}css/blueprint/blueprint/plugins/buttons/buttons.css" type="text/css" media="screen, projection">	
</#if>


<#if widget_refer == 'all' || widget_refer == 'openfire'>
<link href="${beginPath}css/openfire/global.css" rel="stylesheet" type="text/css" />
</#if>


<#if widget_refer == 'all' || widget_refer == 'accordion'>
<script type="text/javascript" src="${beginPath}js/jquery.accordion.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'color_picker'>
<script type="text/javascript" src="${beginPath}js/jquery.colorpicker.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'count_down'>
<script type="text/javascript" src="${beginPath}js/jquery.countdown.js"></script>
<script type="text/javascript" src="${beginPath}js/jquery.countdown.compat.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'chart'>
<script type="text/javascript" src="${beginPath}js/jscharts.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'date_picker'>
<script type="text/javascript" src="${beginPath}js/ui.datepicker.js"></script>
<link href="${beginPath}css/ui.datepicker.css" rel="stylesheet" type="text/css" />
</#if>

<#if widget_refer == 'all' || widget_refer == 'dock'>
<script type="text/javascript" src="${beginPath}js/jquery.dock.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'editor'>
<#assign kindEditorBeginPath = '/swsj/crud/editor/kindeditor/' />
<!--
<script type="text/javascript" charset="utf-8" src="${kindEditorBeginPath}src/lang/zh_CN.js"></script>
<script type="text/javascript" charset="utf-8" src="${kindEditorBeginPath}src/kindeditor-core.js"></script>
<script type="text/javascript" charset="utf-8" src="${kindEditorBeginPath}src/plugin-all.js"></script>
-->
<script type="text/javascript" charset="utf-8" src="${kindEditorBeginPath}build/kindeditor.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'grid'>
<script type="text/javascript" src="${beginPath}js/flexigrid.js"></script>
<link href="${beginPath}css/flexigrid.css" rel="stylesheet" type="text/css" />
</#if>

<#if widget_refer == 'all' || widget_refer == 'messager'>
<script type="text/javascript" src="${beginPath}js/jquery.messager.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'timer'>
<script type="text/javascript" src="${beginPath}js/jquery.timers.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'tree'>
<script type="text/javascript" src="${beginPath}js/jquery.treeview.js"></script>
<link href="${beginPath}css/jquery.treeview.css" rel="stylesheet" type="text/css" />
</#if>

<#if widget_refer == 'all' || widget_refer == 'ui.pack'>
<script type="text/javascript" src="${beginPath}js/jquery-ui-1.6.custom.min.js"></script>
<link href="${beginPath}css/ui.all.css" rel="stylesheet" type="text/css" />
</#if>

<#if widget_refer == 'all' || widget_refer == 'valid'>
<script type="text/javascript" src="${beginPath}js/valid.js"></script>
</#if>

<#if widget_refer == 'all' || widget_refer == 'jniceform'>
<link href="${beginPath}css/jNice.css" rel="stylesheet" type="text/css" />
</#if>
</#list>


<#if ext_js_list?exists>
<#list ext_js_list as ext_js_file>
<script type="text/javascript" src="${beginPath}js/${ext_js_file}"></script>
</#list>
</#if>

<#list default_css_list as ext_css_file>
<link href="${beginPath}css/default/${ext_css_file}" rel="stylesheet" type="text/css" />
</#list>

<#if ext_css_list?exists>
<#list ext_css_list as ext_css_file>
<link href="${beginPath}css/${ext_css_file}" rel="stylesheet" type="text/css" />
</#list>
</#if>

</#macro>
<#-- End Macro: html_head -->

<#-- page header -->
<#macro page_header title="" widget_list=['all'] 
	encoding="utf-8" beginPath="/swsj/zftl/" style="smooth">
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=${encoding}" />
<title>${title}</title>
<@html_head widget_list=widget_list />

<#nested>
</head>
</#macro>
<#-- End Macro: page header -->

<#macro page_body>
<#if body_id?exists>
<body id="${body_id}">
<#else>
<body>
</#if>
<#nested />
</body>
</html>
</#macro>

<#-- End Zftl Macro: Base Defination -->
 

下面的这段是jschart的封装,算例子吧

<#assign style_arr = {
	"blue":  
		{
			"bar_color": "#42aBdB", 
			"bar_border_color": "#D9EDF7", 
			"title_color": "#8C8383",
			"axis_color": "#777E81",
			"axis_name_color": "#777E81",
			"axis_value_color": "#777E81",
			"grid_color": "#ABABAB",
			
			'pie_title_color': '#7A7A7A',
			'pie_units_color': '#fff',
			'pie_values_color': '#878787'
			},
		
	"magenta":  
		{
			"bar_color": "#42aBdB", 
			"bar_border_color": "#bbb", 
			"title_color": "#8C8383",
			"axis_color": "#ABABAB",
			"axis_name_color": "#858585",
			"axis_value_color": "#858585",
			"grid_color": "#ABABAB"
			},
		
		
	"red":  
		{
			"bar_color": "#42aBdB", 
			"bar_border_color": "#D9EDF7", 
			"title_color": "#8C8383",
			"axis_color": "#777E81",
			"axis_value_color": "#777E81"
			}
} />

<#-- Chart Bar -->
<#macro basic_bar chart_div_id="mybarchart" style="blue" barvalue="false" 
	bar_opacity="0.8" bar_space_ratio="50" axis_width="1">
<#assign theme=style_arr[style] />
<#if !theme?exists>
	<#assign theme=style_arr['blue'] />
</#if>
	
<div id="${chart_div_id}">Loading...</div>
<script type="text/javascript">
	var myData = new Array(['2005', 2], ['2006', 1], ['2007', 3], ['2008', 6]);
	var colors = ['#7979DB', '#7952E9', '#792BC8', '#792BA1'];
	<#nested />
	var myChart = new JSChart('${chart_div_id}', 'bar');
	myChart.setDataArray(myData);
	myChart.colorizeBars(colors);
	
	myChart.setBarColor('${theme.bar_color}');
	myChart.setBarBorderColor('${theme.bar_border_color}');
	myChart.setBarValues(${bar_value});
	myChart.setBarSpacingRatio(${bar_space_ratio});
	myChart.setBarValues(${bar_value});
	
	myChart.setTitleColor('${theme.title_color}');
	
	myChart.setAxisColor('${theme.axis_color}');
	myChart.setAxisNameColor('${theme.axis_name_color}');
	myChart.setAxisValuesColor('${theme.axis_value_color}');
	myChart.setAxisWidth(${axis_width});
	
	myChart.setGridColor('${theme.grid_color}');
	myChart.setBarOpacity(${bar_opacity});
	
	myChart.draw();
</script>

</#macro>
<#-- End Macro Chart Bar -->

<#-- Chart Pie -->
<#macro basic_pie chart_div_id="mypiechart" style="blue">
<#assign theme=style_arr[style] />
<#if !theme?exists>
	<#assign theme=style_arr['blue'] />
</#if>
	
<div id="${chart_div_id}">Loading...</div>
<script type="text/javascript">
	var myData = new Array(['S.1', 20], ['S.2', 70], ['S.3', 30], ['S.4', 60], ['S.5', 80], ['S.6', 10]);
	var colors = ['#898A89', '#767776', '#676767', '#434443', '#B0B1B0', '#9E9F9E'];
	<#nested />
	var myChart = new JSChart('${chart_div_id}', 'pie');
	myChart.setDataArray(myData);
	myChart.colorizePie(colors);
	
	myChart.setTitleColor('${theme.pie_title_color}');
	myChart.setPieUnitsColor('${theme.pie_units_color}');
	myChart.setPieValuesColor('${theme.pie_values_color}');
	myChart.draw();
</script>

</#macro>
<#-- End Macro Chart Pie -->
 


Web flow方面——准确的说,我也不知道Web flow的一些相关规范,我所作的只是简单把Crud这些基本操作从view到action到model用代码和模板实现了一下而已,结果就是对一个表/视图,进行crud,只需要定义下这个模型就可以了——我没有扩展Model.class.php,另外用xml形式定义的,过程就是解析加载分析,根据模板分析。

 


辅助工具的使用 ——用过rails/grails的都熟悉下面这些命令吧

create app ***

create controller  model***

generate all ***

 

well,tp既然结构也这么规范,完全也可以用一些命令去简化copy工作——以为php不够熟悉,一些io代码写起来很烂,所以,不得不借助些java平台的东东了——ant,看看下面的命令你就大概明白了

ant create-app Test

ant clear-cache Test

ant delete-app Test

ant create-action Test Index

ant clear-svn Test is_recurve true

*********************

其实都是些很简单的io操作,具体没有涉及到目标代码的动态声称(懒得写了),不过还够用

 

 

终于写完了……汗,继续coding去?

well,祝愿ThinkPHP越来越好,phper越来越像大牛,呵呵

 

 

 

 

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics