<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Terrysco&#039;s Blog &#187; CMS/FrameWork</title>
	<atom:link href="http://www.terrysco.com/node/category/cmsframework/feed" rel="self" type="application/rss+xml" />
	<link>http://www.terrysco.com</link>
	<description>仅关注于互联网行业， Linux平台开发。</description>
	<lastBuildDate>Sat, 05 Nov 2011 21:24:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>用Drupal快速实现mobile平台服务端</title>
		<link>http://www.terrysco.com/node/drupal-as-mobile-backend.html</link>
		<comments>http://www.terrysco.com/node/drupal-as-mobile-backend.html#comments</comments>
		<pubDate>Sat, 05 Nov 2011 21:23:40 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=445</guid>
		<description><![CDATA[用Drupal很容易实现一个API，让手机平台或者其他系统使用json的格式进行通信。 &#60;?php define('API_ERRORNO_INVALID_ACTION', 1); define('API_ERRORNO_INVALID_PARAM', 2); define('API_ERRORNO_NO_RECORD', 3); define('API_ERRORNO_INVALID_NAME', 4); define('API_ERRORNO_USER_BLOCKED', 5); define('API_ERRORNO_LOGIN_FAILED', 6); // 根据错误代码返回错误信息 function api_message_wrapper($errno) { $message = array( API_ERRORNO_INVALID_ACTION =&#62; '非法的请求动作', API_ERRORNO_INVALID_PARAM =&#62; '非法的请求参数', API_ERRORNO_NO_RECORD =&#62; '查找不到数据', API_ERRORNO_INVALID_NAME =&#62; '非法的手机号码', API_ERRORNO_USER_BLOCKED =&#62; '当前用户已经被禁用', API_ERRORNO_LOGIN_FAILED =&#62; '登陆失败', ); return isset($message[$errno]) ? $message[$errno] : '未知的错误'; } // 验证合法的action function api_action_route($action) { $valid_actions = [...]]]></description>
			<content:encoded><![CDATA[<pre>用Drupal很容易实现一个API，让手机平台或者其他系统使用json的格式进行通信。</pre>
<pre>&lt;?php</pre>
<pre>define('API_ERRORNO_INVALID_ACTION', 1);
define('API_ERRORNO_INVALID_PARAM', 2);
define('API_ERRORNO_NO_RECORD', 3);
define('API_ERRORNO_INVALID_NAME', 4);
define('API_ERRORNO_USER_BLOCKED', 5);
define('API_ERRORNO_LOGIN_FAILED', 6);

// 根据错误代码返回错误信息
function api_message_wrapper($errno) {
  $message = array(
    API_ERRORNO_INVALID_ACTION =&gt; '非法的请求动作',
    API_ERRORNO_INVALID_PARAM =&gt; '非法的请求参数',
    API_ERRORNO_NO_RECORD =&gt; '查找不到数据',
    API_ERRORNO_INVALID_NAME =&gt; '非法的手机号码',
    API_ERRORNO_USER_BLOCKED =&gt; '当前用户已经被禁用',
    API_ERRORNO_LOGIN_FAILED =&gt; '登陆失败',
  );
  return isset($message[$errno]) ? $message[$errno] : '未知的错误';
}

// 验证合法的action
function api_action_route($action) {
  $valid_actions = array(
      'login' =&gt; 'login',
      'register' =&gt; 'register',
      'getCardInfos' =&gt; 'get_card_info',
  );
  return isset($valid_actions[$action]) ? $valid_actions[$action] : false;
}

function api_menu() {
  $items['api'] = array(
    'page callback' =&gt; 'api_dispatch',
    'access callback' =&gt; TRUE,
    //'access arguments' =&gt; array('使用API'),
    'type' =&gt; MENU_CALLBACK,
    'file' =&gt; 'api.functions.inc',
  );
  return $items;
}

// 成功返回
function api_response_sucess($data) {
  drupal_json(array('ERRNO' =&gt; 0, 'DATA' =&gt; $data));
}

// 失败返回
function api_response_error($errno) {
  if ($errno &amp;&amp; is_numeric($errno)) {
    drupal_json(array(
      'ERRNO' =&gt; $errno,
      'MSG' =&gt; api_message_wrapper($errno),
    ));
  }
}

// API调度入口
function api_dispatch() {
  if (!isset($_POST['ACTION']) || !api_action_route($_POST['ACTION'])) {
    api_response_error(API_ERRORNO_INVALID_ACTION);
  }
  elseif (!isset($_POST['PARAM'])) {
    api_response_error(API_ERRORNO_INVALID_PARAM);
  }
  else {
    $param = json_decode($_POST['PARAM']);
    call_user_func('api_call_'.  api_action_route($_POST['ACTION']), $param);
  }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/drupal-as-mobile-backend.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用yii框架开发web应用</title>
		<link>http://www.terrysco.com/node/%e7%94%a8yii%e6%a1%86%e6%9e%b6%e5%bc%80%e5%8f%91web%e5%ba%94%e7%94%a8.html</link>
		<comments>http://www.terrysco.com/node/%e7%94%a8yii%e6%a1%86%e6%9e%b6%e5%bc%80%e5%8f%91web%e5%ba%94%e7%94%a8.html#comments</comments>
		<pubDate>Fri, 08 Jul 2011 13:24:04 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=432</guid>
		<description><![CDATA[好久没写博客了，都是在微博中堕落了，加上最近特别忙，入手了一台MBP。更换了工作平台，准备看些新的适合web2.0的高性能纯面向对象框架，yii就是我想要的了。 官方文档比较齐全，有多语言在线文档和两本pdf书籍以及一个用yii搭建blog程序的向导。学习曲线不算曲折，很快就上手用它来写东西。特性一大堆，刚开始不可能熟悉所有的，只是看了数据库和用户验证以及表单部分，一般的web应用就能应付了。至于怎么让yii更好的为你工作，完全深入它的很多机制只能在接下来的时间中慢慢熟悉。对于从别的mvc模式的框架转移到yii，几乎不用花费太多时间。有两个图看明白了概念也就清晰了，一个是路由处理的流程图，一个是mvc加上组件以及其他附属品的结构图。 繁忙的生活让我最近颓废了好多，以前2个星期一本书的习惯已经荒废了半年了，打算10-1后振作下，坚持下去这个习惯。近期打算翻译一些网络安全书籍，给drupal社区提交一些开源模块，尝试一些新鲜的东西。]]></description>
			<content:encoded><![CDATA[<p>好久没写博客了，都是在微博中堕落了，加上最近特别忙，入手了一台MBP。更换了工作平台，准备看些新的适合web2.0的高性能纯面向对象框架，yii就是我想要的了。</p>
<p>官方文档比较齐全，有多语言在线文档和两本pdf书籍以及一个用yii搭建blog程序的向导。学习曲线不算曲折，很快就上手用它来写东西。特性一大堆，刚开始不可能熟悉所有的，只是看了数据库和用户验证以及表单部分，一般的web应用就能应付了。至于怎么让yii更好的为你工作，完全深入它的很多机制只能在接下来的时间中慢慢熟悉。对于从别的mvc模式的框架转移到yii，几乎不用花费太多时间。有两个图看明白了概念也就清晰了，一个是路由处理的流程图，一个是mvc加上组件以及其他附属品的结构图。</p>
<p>繁忙的生活让我最近颓废了好多，以前2个星期一本书的习惯已经荒废了半年了，打算10-1后振作下，坚持下去这个习惯。近期打算翻译一些网络安全书籍，给drupal社区提交一些开源模块，尝试一些新鲜的东西。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/%e7%94%a8yii%e6%a1%86%e6%9e%b6%e5%bc%80%e5%8f%91web%e5%ba%94%e7%94%a8.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Drupal编程总结</title>
		<link>http://www.terrysco.com/node/drupal-programming-summary.html</link>
		<comments>http://www.terrysco.com/node/drupal-programming-summary.html#comments</comments>
		<pubDate>Wed, 22 Dec 2010 10:35:17 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=412</guid>
		<description><![CDATA[从2007年末接触Drupal开始，已经3年时间了。Drupal已经从5.x版本升级到了7.x，模块开发也发生了很多变化。 1. 在查询数据库的时候，考虑到一些特殊情况尽量使用静态变量，这相当于drupal的第一层缓存，在drupal的很多load相关函数中到处可见。比如： function terrysco_get_group($lgid, $reset = false) { // 使用静态变量做缓存 static $linkedin = array(); if ($reset) { $terrysco = array(); } if (!isset($terrysco[$lgid]) &#38;&#38; is_numeric($lgid)) { $terrysco[$lgid] = db_fetch_array(db_query(&#8216;SELECT * FROM {linkedin_groups} WHERE lgid = %d&#8217;, $lgid)); } return isset($terrysco[$lgid]) ? $terrysco[$lgid] : false; } 这样，在要处理一个大的结果集的时候，在循环中调用该函数，就不会每次循环都查询数据库了。 2. 深入理解drupal的hook机制，用好module_invoke_all来设计你的模块机制，大大增强扩展性。其他方面，多想想怎么和别的模块工作的更好，不要进行hack的工作，要给别的模块留下更改你输出主题，更改你返回数据的机会。 3. 多使用表单给用户进行参数配置，将这些配置用variable_set存起来随时使用，生成配置表单的时候可以使用system_settings_form()将表单数组包装起来，省去了写提交函数的部分。另外，将一些数据分析后可以适当存储在session或者cookie中，不一定非要写数据库。 4. 不要过于依赖node机制。node给我们提供了很多方便，很多第三方模块装上后就能很好的工作，比如fivestar，views之类的东西，但也要考虑实际项目需要。很多小的数据如果量很大，不建议放在node表中。而且node表以nid作为auto_increment的primary key，给我们日后做扩展留下了很多麻烦。 5. [...]]]></description>
			<content:encoded><![CDATA[<p>从2007年末接触Drupal开始，已经3年时间了。Drupal已经从5.x版本升级到了7.x，模块开发也发生了很多变化。</p>
<p>1. 在查询数据库的时候，考虑到一些特殊情况尽量使用静态变量，这相当于drupal的第一层缓存，在drupal的很多load相关函数中到处可见。比如：</p>
<p>function terrysco_get_group($lgid, $reset = false) {</p>
<p> // 使用静态变量做缓存</p>
<p> static $linkedin = array();</p>
<p> if ($reset) {</p>
<p> $terrysco = array();</p>
<p> }</p>
<p> if (!isset($terrysco[$lgid]) &amp;&amp; is_numeric($lgid)) {</p>
<p> $terrysco[$lgid] = db_fetch_array(db_query(&#8216;SELECT * FROM {linkedin_groups} WHERE lgid = %d&#8217;, $lgid));</p>
<p> }</p>
<p> return isset($terrysco[$lgid]) ? $terrysco[$lgid] : false;</p>
<p>}</p>
<p>这样，在要处理一个大的结果集的时候，在循环中调用该函数，就不会每次循环都查询数据库了。</p>
<p>2. 深入理解drupal的hook机制，用好module_invoke_all来设计你的模块机制，大大增强扩展性。其他方面，多想想怎么和别的模块工作的更好，不要进行hack的工作，要给别的模块留下更改你输出主题，更改你返回数据的机会。</p>
<p>3. 多使用表单给用户进行参数配置，将这些配置用variable_set存起来随时使用，生成配置表单的时候可以使用system_settings_form()将表单数组包装起来，省去了写提交函数的部分。另外，将一些数据分析后可以适当存储在session或者cookie中，不一定非要写数据库。</p>
<p>4. 不要过于依赖node机制。node给我们提供了很多方便，很多第三方模块装上后就能很好的工作，比如fivestar，views之类的东西，但也要考虑实际项目需要。很多小的数据如果量很大，不建议放在node表中。而且node表以nid作为auto_increment的primary key，给我们日后做扩展留下了很多麻烦。</p>
<p>5. 不要过于依赖第三方模块。第三方模块的一个共同点就是功能强大，代码质量还算不错，但是正因为如此，模块开发者考虑到的是通用性，一个大的模块可能很多功能我们使用不了，这时候就不要偷懒了，自己动手吧。而且很多第三方模块是有问题的，自己细心研究下就能发现很多。</p>
<p>6. Drupal本身支持快速切换数据库，这就使得我们可以在开始的时候就做好设计，看看是否将某些业务分离。当然，如果是中小型的项目就不用了。</p>
</p>
<p>未完待续。。。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/drupal-programming-summary.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP Application Development</title>
		<link>http://www.terrysco.com/node/cakephp-kickoff.html</link>
		<comments>http://www.terrysco.com/node/cakephp-kickoff.html#comments</comments>
		<pubDate>Mon, 11 Oct 2010 11:20:45 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[Book Remarks]]></category>
		<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=363</guid>
		<description><![CDATA[花了三天时间看完了《CakePHP Application Development》这本PDF文档，感叹作者的耐心，何奇的淡定。且不说我这个用了PHP做应用5年的人，就算是一个PHP不怎么了解的人估计都能看懂。这本书从头到尾都在案例之后进行分析，我觉得好处在于对初学者来说在cakephp这个框架能打好基础，对cakephp的个方面了解比较透彻。虽然从头到尾300多页感觉如果精简的话可能只有100多页，但是我不认为多余的是废话。只有对技术比较刨根问底的人才能把一门技术写的请清楚楚，让看客们也请清楚楚，明明白白。比起其他一些作者，写出来的东西都是一律而过来得更为实在。 cakephp是基于MVC这个模式来组织代码的，所以此书最重要的三章应该就是分别介绍controller，model和view的三章。早就听说cakephp是ror的php版本，虽然说法有些夸张，但是在cake里面还是能看到很多ror的思想和影子。很多人也说cake的Model实现方式过为复杂，我想只是使用群体不一样，具体的项目具体对待。 这次是因为一个中型项目而让我对cakephp产生要了解的想法。因为虽然php的framework很多，但是不像java阵营那样，php相关的框架大都是毁誉参半的，而且个别流行的框架也没有强大的社区支持。从众多的php框架中我选择了国产的thinkphp，相当于官方的zend framework以及轻量级的codeigiter，最后就是本文主要介绍的cakephp。选择的过程是个纠结的过程，因为框架的选择角度太多了，但从代码风格上来说，我更趋向于cake的代码。仔细研究了下，发现cake做的很人性化，这里人性化的意思是作者很像是个做产品的人，因为从很多地方都体现出了cake的方便和人性化。比如scaffold这个基本功能，在codeigiter里面也有，cake里面只需要在controller里面声明一个scaffold属性就行了，相当简单。 大家都知道，较高的便利性下面都隐藏着大量的命名约定。因为你只有遵守了框架作者的约定和设计思想，你才会得到很大的便利。因为作者在设计的时候，如果考虑使用者各种各样的习惯，设计出来的东西谁都用着不舒服了，只有使用者遵循一定的规则，框架就能带来强大的生产力，这也就是cake的脚本可以跑起来的前提条件。cake拥有一个小型的“shell”，叫做bake，ROR和Djangle都有类似的支持。只要我们在controller，model和views以及数据库设计的时候遵循了cake的命名约定，那么这一些都可以用bake来帮你处理。 我用cakephp建立了一个简单的定餐应用，发现确实像口号中所说那样：rapid development。大概一个下午，就做出了一个成熟的定餐系统应该有的所有功能。这样我就不用羡慕很多java开发者可以使用成熟的框架了，没办法自己对java也挺了解的，为什么就没法在实际应用中应用呢？总觉得太重。 搜索cakephp的时候，在网上看到一些中文资料，但质量都不是很好，强烈建议对cakephp有兴趣的朋友看看这本书，从头到尾没有一个晦涩的单词，通俗易懂。而且后面几章作者通过一个实例小应用配合cake的一些特性进行了说明，这写特性有分页，ajax，认证机制，cookie，session，rss订阅。在这写应用中，cake都显得极为方便。正如那句话：a piece of cake。 本书是面向cakephp新手的书，看完后我觉得还需要对官方文档详细阅读后才能达到用cakephp来开发复杂应用的程度。因为用户群不同，这本书只是介绍了cake的一些基础理论，而了解了这写，使用者可以在官方文档中自助式查询需要的东西。]]></description>
			<content:encoded><![CDATA[<p><a href="http://img3.douban.com/lpic/s3195692.jpg"><img class="alignleft" title="CakePHP" src="http://img3.douban.com/lpic/s3195692.jpg" alt="" width="254" height="334" /></a></p>
<p>花了三天时间看完了《CakePHP Application Development》这本PDF文档，感叹作者的耐心，何奇的淡定。且不说我这个用了PHP做应用5年的人，就算是一个PHP不怎么了解的人估计都能看懂。这本书从头到尾都在案例之后进行分析，我觉得好处在于对初学者来说在cakephp这个框架能打好基础，对cakephp的个方面了解比较透彻。虽然从头到尾300多页感觉如果精简的话可能只有100多页，但是我不认为多余的是废话。只有对技术比较刨根问底的人才能把一门技术写的请清楚楚，让看客们也请清楚楚，明明白白。比起其他一些作者，写出来的东西都是一律而过来得更为实在。</p>
<p>cakephp是基于MVC这个模式来组织代码的，所以此书最重要的三章应该就是分别介绍controller，model和view的三章。早就听说cakephp是ror的php版本，虽然说法有些夸张，但是在cake里面还是能看到很多ror的思想和影子。很多人也说cake的Model实现方式过为复杂，我想只是使用群体不一样，具体的项目具体对待。</p>
<p>这次是因为一个中型项目而让我对cakephp产生要了解的想法。因为虽然php的framework很多，但是不像java阵营那样，php相关的框架大都是毁誉参半的，而且个别流行的框架也没有强大的社区支持。从众多的php框架中我选择了国产的thinkphp，相当于官方的zend framework以及轻量级的codeigiter，最后就是本文主要介绍的cakephp。选择的过程是个纠结的过程，因为框架的选择角度太多了，但从代码风格上来说，我更趋向于cake的代码。仔细研究了下，发现cake做的很人性化，这里人性化的意思是作者很像是个做产品的人，因为从很多地方都体现出了cake的方便和人性化。比如scaffold这个基本功能，在codeigiter里面也有，cake里面只需要在controller里面声明一个scaffold属性就行了，相当简单。</p>
<p>大家都知道，较高的便利性下面都隐藏着大量的命名约定。因为你只有遵守了框架作者的约定和设计思想，你才会得到很大的便利。因为作者在设计的时候，如果考虑使用者各种各样的习惯，设计出来的东西谁都用着不舒服了，只有使用者遵循一定的规则，框架就能带来强大的生产力，这也就是cake的脚本可以跑起来的前提条件。cake拥有一个小型的“shell”，叫做bake，ROR和Djangle都有类似的支持。只要我们在controller，model和views以及数据库设计的时候遵循了cake的命名约定，那么这一些都可以用bake来帮你处理。</p>
<p>我用cakephp建立了一个简单的定餐应用，发现确实像口号中所说那样：rapid development。大概一个下午，就做出了一个成熟的定餐系统应该有的所有功能。这样我就不用羡慕很多java开发者可以使用成熟的框架了，没办法自己对java也挺了解的，为什么就没法在实际应用中应用呢？总觉得太重。</p>
<p>搜索cakephp的时候，在网上看到一些中文资料，但质量都不是很好，强烈建议对cakephp有兴趣的朋友看看这本书，从头到尾没有一个晦涩的单词，通俗易懂。而且后面几章作者通过一个实例小应用配合cake的一些特性进行了说明，这写特性有分页，ajax，认证机制，cookie，session，rss订阅。在这写应用中，cake都显得极为方便。正如那句话：a piece of cake。</p>
<p>本书是面向cakephp新手的书，看完后我觉得还需要对官方文档详细阅读后才能达到用cakephp来开发复杂应用的程度。因为用户群不同，这本书只是介绍了cake的一些基础理论，而了解了这写，使用者可以在官方文档中自助式查询需要的东西。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/cakephp-kickoff.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CodeIgniter 入门</title>
		<link>http://www.terrysco.com/node/codeigniter-introduction.html</link>
		<comments>http://www.terrysco.com/node/codeigniter-introduction.html#comments</comments>
		<pubDate>Mon, 29 Mar 2010 05:20:11 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[Book Remarks]]></category>
		<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[codeigniter]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=331</guid>
		<description><![CDATA[终于花了1个半星期的时间看完了“CodeIgniter 1.7”这本书，300多页，不过内容还算丰富。从web开发的各个方面介绍了CodeIgniter这个PHP框架，章节的安排跟那本“Pro Drupal Development”类似。看完本书后，感觉codeigniter确实能弥补一些目前的PHP框架开发现状，目前来说基于PHP的CMS比较全，国外流行的有drupal，joomla，CMSMS等等，国内的就更数不胜数了。但提到framework，大家都想到zend framework，研究过一段时间这个框架，感觉过于庞大了，至于剩下的cakePHP，thinkPHP，国内的FleaPHP都没有涉及过，第一个接触的正式PHP框架（正式是针对drupal来说）就是CodeIgniter了。 使用drupal2年多，已经身心疲惫。总是感觉还不是那么的灵活，性能还不是那么的好，总想对它控制得更多，但我们能做的只有hook。不可否认，drupal在快速搭建一些中小型站点确实是不错的选择，模块很多，社区很活跃，但是如果用来开发一些大型的应用就显得力不从心了，比如我们开发一个万人活跃用户的SNS社区，一个多应用服务器架构的系统。drupal本身是面向过程的PHP通过HOOK机制组织起来的，这时我们就迫切需要一款MVC的面向对象设计的框架。codeigniter正是如此。 比较喜欢CI（codeigniter的简称）的一些设计理念，第一个就是从不强迫用户，CI为开发者提供了很多功能（helper，plugin，library等等），方便开发者，但它不强迫你使用这些功能，你完全可以自定义开发自己的功能模块，甚至可以很方便的集成第三方工具进来，不像drupal，你必须对drupal机制要很了解，才能做一些比较深入的工作。另外，CI的定制性很高，你可以参考CI的文档对其任意定制，足以迷惑用户是不是CI开发出来的站点。 网上有一个老外做的视频，20分钟用CI搭建一个blog系统，虽说有些夸张，但功能也太简陋了，不管是安全性还是UE都没有考虑太多，我做过一个测试，3-4个小时开发出来一套多用户blog系统是完全可行的。 此外，CI为我们提供了很多类库，涵盖的功能如下： 文件下载 邮件发送，可包含附件 表单 FTP 分页 。。。 CodeIgniter，值得学习。]]></description>
			<content:encoded><![CDATA[<p><a href="http://img3.douban.com/lpic/s4239382.jpg"><img class="alignnone" title="CodeIgniter" src="http://img3.douban.com/lpic/s4239382.jpg" alt="" width="327" height="405" /></a></p>
<p>终于花了1个半星期的时间看完了“CodeIgniter 1.7”这本书，300多页，不过内容还算丰富。从web开发的各个方面介绍了CodeIgniter这个PHP框架，章节的安排跟那本“Pro Drupal Development”类似。看完本书后，感觉codeigniter确实能弥补一些目前的PHP框架开发现状，目前来说基于PHP的CMS比较全，国外流行的有drupal，joomla，CMSMS等等，国内的就更数不胜数了。但提到framework，大家都想到zend framework，研究过一段时间这个框架，感觉过于庞大了，至于剩下的cakePHP，thinkPHP，国内的FleaPHP都没有涉及过，第一个接触的正式PHP框架（正式是针对drupal来说）就是CodeIgniter了。</p>
<p>使用drupal2年多，已经身心疲惫。总是感觉还不是那么的灵活，性能还不是那么的好，总想对它控制得更多，但我们能做的只有hook。不可否认，drupal在快速搭建一些中小型站点确实是不错的选择，模块很多，社区很活跃，但是如果用来开发一些大型的应用就显得力不从心了，比如我们开发一个万人活跃用户的SNS社区，一个多应用服务器架构的系统。drupal本身是面向过程的PHP通过HOOK机制组织起来的，这时我们就迫切需要一款MVC的面向对象设计的框架。codeigniter正是如此。</p>
<p>比较喜欢CI（codeigniter的简称）的一些设计理念，第一个就是从不强迫用户，CI为开发者提供了很多功能（helper，plugin，library等等），方便开发者，但它不强迫你使用这些功能，你完全可以自定义开发自己的功能模块，甚至可以很方便的集成第三方工具进来，不像drupal，你必须对drupal机制要很了解，才能做一些比较深入的工作。另外，CI的定制性很高，你可以参考CI的文档对其任意定制，足以迷惑用户是不是CI开发出来的站点。</p>
<p>网上有一个老外做的视频，20分钟用CI搭建一个blog系统，虽说有些夸张，但功能也太简陋了，不管是安全性还是UE都没有考虑太多，我做过一个测试，3-4个小时开发出来一套多用户blog系统是完全可行的。</p>
<p>此外，CI为我们提供了很多类库，涵盖的功能如下：</p>
<ul>
<li>文件下载</li>
<li>邮件发送，可包含附件</li>
<li>表单</li>
<li>FTP</li>
<li>分页</li>
</ul>
<p>。。。</p>
<p>CodeIgniter，值得学习。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/codeigniter-introduction.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>关于drupal架构的思考</title>
		<link>http://www.terrysco.com/node/drupal-extension.html</link>
		<comments>http://www.terrysco.com/node/drupal-extension.html#comments</comments>
		<pubDate>Fri, 11 Dec 2009 09:58:11 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=289</guid>
		<description><![CDATA[自从drupalchina推荐我的blog后，很多drupal的开发者和我讨论drupal的性能，drupal的缺陷，大有感触。 很多人都说drupal站点不适合扩展，或者简单的做到数据库和代码分离后就茫然了。最近参考了很多软件和web架构的书，反过来对drupal这个系统做了一些关于架构扩展的思考。 以自己现有水平来看，drupal的瓶颈似乎在PHP代码执行层面。网上说使用APC加速可以大大加强drupal的性能，自己还没有手动进行测试，所以没有发言权。但目前在自己使用过程中，还是看到drupal一些小尴尬。 drupal的缓存系统比较简单，只是对匿名用户（因为匿名用户访问页面变更比较少）进行页面缓存，并且是以数据库的形式进行缓存。直接序列化页面到cache_page表中，这种性能可想而知，如果对百万级的访问量来说，db将会是个噩梦。 drupal用apache的rewrite模块实现了简洁链接，伪静态页面是提高了SEO效果，但是针对生成静态页面来说，还是比较困难的。另外，drupal的代码可以更加精简，否则为了强大的扩展性损失大幅性能也是不可取的。 有人说代码和架构扩展没有关系（忘记哪位大牛说的），其实我不是很赞同这句话，代码和数据库刚开始的设计决定或者制约了很多后面需要扩展的条件，比如水平划分数据库表的时候，最好是选取primary key，但是这个字段最好不是auto_increment的（道理很容易想到），再比如数据库抽象层的代码如果做memcache缓存，好修改吗？ 很多时候，代码级别制约扩展性的很大一个因素就是联合查询，因为在做垂直划分数据库的时候，分离的都是一些关联性不大，并且不会牵扯到联合查询的库表，但drupal很多地方都使用的inner join（几乎每个模块都能看到）。当用户并发数越来越大，服务器最大的压力来源于数据库，这时，有些朋友就说了”负载均衡“啊。 没有那么简单，首先我们考虑基于重定向的负载均衡，多做几个后端服务器，使用RR或者简单随即抽取机制来轮流使用服务器，drupal和其他站点不同的一点小小特性就是唯一入口index.php，也就是说在这个文件我们可以写入一些代码，实现重定向的负载均衡，这点是比较合适的。或者您为了避免不是真正的压力平衡，可以使用DNS负载均衡，这样下来，稍微大点的数据量我们勉强顶得住了。 从水平划分的方面来看，首先最大的表应该是drupal的node表，nid字段是primary key,并且auto_increment的，这就很难进行分表存储。另外就算使用了一些别的算法，分N个表出来存储node，问题是如果使那些众多的node相关操作代码使用不会出问题？ 另外一种做法就是使用ngnix的反向代理功能，很多java的开发者叫分布式。就算后端服务器性能差异，我们还是可以通过配置文件来决定权重，能者多得的方式，让每个机器发挥到极限。还可以考虑的方式就是使用apache加载我们定义的lua脚本，匹配select和insert，update，delete等字符串，用来区分属于何种sql查询，进一步实现读写分离。不过在机器之间的数据同步也是个麻烦的事情，我没有在运维方面有多少经验，最多就是使用过rsync。 分析种种情景，使用drupal的用户不要担心，只要我们想的到，可扩展的办法还是很多的。性能决定在你自己手里。]]></description>
			<content:encoded><![CDATA[<p>自从drupalchina推荐我的blog后，很多drupal的开发者和我讨论drupal的性能，drupal的缺陷，大有感触。</p>
<p>很多人都说drupal站点不适合扩展，或者简单的做到数据库和代码分离后就茫然了。最近参考了很多软件和web架构的书，反过来对drupal这个系统做了一些关于架构扩展的思考。</p>
<p>以自己现有水平来看，drupal的瓶颈似乎在PHP代码执行层面。网上说使用APC加速可以大大加强drupal的性能，自己还没有手动进行测试，所以没有发言权。但目前在自己使用过程中，还是看到drupal一些小尴尬。</p>
<p>drupal的缓存系统比较简单，只是对匿名用户（因为匿名用户访问页面变更比较少）进行页面缓存，并且是以数据库的形式进行缓存。直接序列化页面到cache_page表中，这种性能可想而知，如果对百万级的访问量来说，db将会是个噩梦。</p>
<p>drupal用apache的rewrite模块实现了简洁链接，伪静态页面是提高了SEO效果，但是针对生成静态页面来说，还是比较困难的。另外，drupal的代码可以更加精简，否则为了强大的扩展性损失大幅性能也是不可取的。</p>
<p>有人说代码和架构扩展没有关系（忘记哪位大牛说的），其实我不是很赞同这句话，代码和数据库刚开始的设计决定或者制约了很多后面需要扩展的条件，比如水平划分数据库表的时候，最好是选取primary key，但是这个字段最好不是auto_increment的（道理很容易想到），再比如数据库抽象层的代码如果做memcache缓存，好修改吗？</p>
<p>很多时候，代码级别制约扩展性的很大一个因素就是联合查询，因为在做垂直划分数据库的时候，分离的都是一些关联性不大，并且不会牵扯到联合查询的库表，但drupal很多地方都使用的inner join（几乎每个模块都能看到）。当用户并发数越来越大，服务器最大的压力来源于数据库，这时，有些朋友就说了”负载均衡“啊。</p>
<p>没有那么简单，首先我们考虑基于重定向的负载均衡，多做几个后端服务器，使用RR或者简单随即抽取机制来轮流使用服务器，drupal和其他站点不同的一点小小特性就是唯一入口index.php，也就是说在这个文件我们可以写入一些代码，实现重定向的负载均衡，这点是比较合适的。或者您为了避免不是真正的压力平衡，可以使用DNS负载均衡，这样下来，稍微大点的数据量我们勉强顶得住了。</p>
<p>从水平划分的方面来看，首先最大的表应该是drupal的node表，nid字段是primary key,并且auto_increment的，这就很难进行分表存储。另外就算使用了一些别的算法，分N个表出来存储node，问题是如果使那些众多的node相关操作代码使用不会出问题？</p>
<p>另外一种做法就是使用ngnix的反向代理功能，很多java的开发者叫分布式。就算后端服务器性能差异，我们还是可以通过配置文件来决定权重，能者多得的方式，让每个机器发挥到极限。还可以考虑的方式就是使用apache加载我们定义的lua脚本，匹配select和insert，update，delete等字符串，用来区分属于何种sql查询，进一步实现读写分离。不过在机器之间的数据同步也是个麻烦的事情，我没有在运维方面有多少经验，最多就是使用过rsync。</p>
<p>分析种种情景，使用drupal的用户不要担心，只要我们想的到，可扩展的办法还是很多的。性能决定在你自己手里。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/drupal-extension.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>定制wordpress的文章发布</title>
		<link>http://www.terrysco.com/node/wordpress-meta-box.html</link>
		<comments>http://www.terrysco.com/node/wordpress-meta-box.html#comments</comments>
		<pubDate>Thu, 05 Nov 2009 04:04:16 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=287</guid>
		<description><![CDATA[wordpress在发布文章的时候，已经集成了很多特性，比如tinyMCE这个可视化编辑器，文章标签（tags），别名（alias），以及分类（taxonomy）。但对于一个基于wordpress的项目，我们仍然需要对其高度定制，wordpress为我们提供了add_meta_box，来优雅的解决这个问题。 用起来比较简单，就6个参数，其中第三个参数为callback。我们可以在这个callback中设置一些输出信息，或者一个表单，最常用的还是后者。比如我们设置一个textarea的文本区域，用来保存一些用户输入的信息，这样用户发布这个post或者page的时候，这个信息就会保存到postmeta表里。其次，我们可以使用get_post_meta来获取这个数据。说到这里，有必要简单提下wordpress的表结构。 不像drupal那么复杂，wordpress主要的内容信息其实就两个表，一个post表，一个postmeta表，前者存放用户发布的基本内容，比如一篇blog，后者存放这个内容的一些附加信息，比如我们刚才定制的那个textarea。 最后，这里说下我碰到的一个问题以及自己的解决办法。在使用add_meta_box的时候，我们只是给post这个表单加入了一些输入控件，如果要处理文件的上传，或者使用curl等库来处理更高级的http操作，就出现问题了。因为form这个表单本身在wordpress中就定义好了，我们知道如果上传文件，form表单必须设置enctype = “multipart/form-data”属性，但默认的是没有的。google大叔告诉我很多人直接修改了wordpress的core，但我觉得这不是一个好的处理方式，我的解决办法是加入一段javascript来动态修改。 window.onload = function() { var form = document.getElementById(“post”); form.enctype = “multipart/form-data”; }; 这段javascript可以替换为更好的jquery代码，因为jquery等很多javascript类库已经集成到wordpress里面。目前能想到的就是这种方式，或许我还不够了解wordpress的机制？]]></description>
			<content:encoded><![CDATA[<p>wordpress在发布文章的时候，已经集成了很多特性，比如tinyMCE这个可视化编辑器，文章标签（tags），别名（alias），以及分类（taxonomy）。但对于一个基于wordpress的项目，我们仍然需要对其高度定制，wordpress为我们提供了add_meta_box，来优雅的解决这个问题。</p>
<p>用起来比较简单，就6个参数，其中第三个参数为callback。我们可以在这个callback中设置一些输出信息，或者一个表单，最常用的还是后者。比如我们设置一个textarea的文本区域，用来保存一些用户输入的信息，这样用户发布这个post或者page的时候，这个信息就会保存到postmeta表里。其次，我们可以使用get_post_meta来获取这个数据。说到这里，有必要简单提下wordpress的表结构。</p>
<p>不像drupal那么复杂，wordpress主要的内容信息其实就两个表，一个post表，一个postmeta表，前者存放用户发布的基本内容，比如一篇blog，后者存放这个内容的一些附加信息，比如我们刚才定制的那个textarea。</p>
<p>最后，这里说下我碰到的一个问题以及自己的解决办法。在使用add_meta_box的时候，我们只是给post这个表单加入了一些输入控件，如果要处理文件的上传，或者使用curl等库来处理更高级的http操作，就出现问题了。因为form这个表单本身在wordpress中就定义好了，我们知道如果上传文件，form表单必须设置enctype = “multipart/form-data”属性，但默认的是没有的。google大叔告诉我很多人直接修改了wordpress的core，但我觉得这不是一个好的处理方式，我的解决办法是加入一段javascript来动态修改。<br />
window.onload = function() {<br />
	var form = document.getElementById(“post”);<br />
	form.enctype = “multipart/form-data”;<br />
};<br />
这段javascript可以替换为更好的jquery代码，因为jquery等很多javascript类库已经集成到wordpress里面。目前能想到的就是这种方式，或许我还不够了解wordpress的机制？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/wordpress-meta-box.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>初涉wordpress开发</title>
		<link>http://www.terrysco.com/node/wordpress-starting.html</link>
		<comments>http://www.terrysco.com/node/wordpress-starting.html#comments</comments>
		<pubDate>Mon, 02 Nov 2009 10:23:30 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=285</guid>
		<description><![CDATA[近期涉及到wordpress-MU版本的开发工作，因为用户对其插件buddypress比较感兴趣。看了两天的文档，感慨wordpress文档的匮乏。。。 除了少的可怜的官方文档，基于codex系统，很多页面都没有书写外，自己down了一份plugin development的pdf，看完这个pdf才有点插件开发的感觉。写了4-5个小插件，熟悉了下wordpress的hook（wp中称作action和filter）。感觉还是不如drupal的模块优雅和灵活，但定制一个系统还是比较简单的，最大的痛苦就是wordpress的api函数太多，而很多都没有文档，不知道该如何选择，看了很多sample，用的还都不一样，版本之间留有差异性，不像drupal，5.x和6.x之间分别保持统一。 目前看来，一个buddypress新建一个用户，数据库中会多出8个表，这个恐怖的事实在网上已经有商业插件解决，不知道这个项目到底是怎么回事？ 另外，视频方面采用了vimeo，开发和调试阶段颇为麻烦，因为国内的防火墙墙掉了很多应用，vimeo也不例外，使用vpn虽然解决了这个问题，但文档和wordpress一样少的可怜。 经过5天的google和编码，还算有点收获，过几天不忙了整理点文档共享给wordpress的插件开发者们。感慨：好的开源项目，如果文档不完善，依然是一件痛苦的事情。]]></description>
			<content:encoded><![CDATA[<p>近期涉及到wordpress-MU版本的开发工作，因为用户对其插件buddypress比较感兴趣。看了两天的文档，感慨wordpress文档的匮乏。。。</p>
<p>除了少的可怜的官方文档，基于codex系统，很多页面都没有书写外，自己down了一份plugin development的pdf，看完这个pdf才有点插件开发的感觉。写了4-5个小插件，熟悉了下wordpress的hook（wp中称作action和filter）。感觉还是不如drupal的模块优雅和灵活，但定制一个系统还是比较简单的，最大的痛苦就是wordpress的api函数太多，而很多都没有文档，不知道该如何选择，看了很多sample，用的还都不一样，版本之间留有差异性，不像drupal，5.x和6.x之间分别保持统一。</p>
<p>目前看来，一个buddypress新建一个用户，数据库中会多出8个表，这个恐怖的事实在网上已经有商业插件解决，不知道这个项目到底是怎么回事？<br />
另外，视频方面采用了vimeo，开发和调试阶段颇为麻烦，因为国内的防火墙墙掉了很多应用，vimeo也不例外，使用vpn虽然解决了这个问题，但文档和wordpress一样少的可怜。</p>
<p>经过5天的google和编码，还算有点收获，过几天不忙了整理点文档共享给wordpress的插件开发者们。感慨：好的开源项目，如果文档不完善，依然是一件痛苦的事情。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/wordpress-starting.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>给drupal批量导入外部数据</title>
		<link>http://www.terrysco.com/node/drupal-colletion-info.html</link>
		<comments>http://www.terrysco.com/node/drupal-colletion-info.html#comments</comments>
		<pubDate>Fri, 16 Oct 2009 12:37:11 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=276</guid>
		<description><![CDATA[很多时候，我们想给自己的drupal站点批量导入节点数据，其中包括很多方法，例如csv格式文件的导入，通过别的站点抓取到得信息，整合别的系统时，相互数据的迁移都要用到这些内容。我们建立一个简单的模型，只考虑节点基本数据，不考虑其他因素（比如节点图片，节点术语分类等等），将模型简单化有助于我们解决问题。 以拿抓取页面为例，我们使用正则表达式过滤出需要的信息后，将其存放在一个一维关联数组中，其中键对应数据库中的节点字段，比如title，body，name。。。然后我们手动调用node_submit方法，将一维数组传进去，这个方法会对我们的数组做一些存表之前的工作，我们直接可以在api.drupal.org查看这个方法的代码。 &#60;?php function node_submit($node) { global $user; // Convert the node to an object, if necessary. $node = (object)$node; // Auto-generate the teaser, but only if it hasn't been set (e.g. by a // module-provided 'teaser' form item). if (!isset($node-&#62;teaser)) { $node-&#62;teaser = isset($node-&#62;body) ? node_teaser($node-&#62;body, isset($node-&#62;format) ? $node-&#62;format : NULL) : ''; } [...]]]></description>
			<content:encoded><![CDATA[<p>很多时候，我们想给自己的drupal站点批量导入节点数据，其中包括很多方法，例如csv格式文件的导入，通过别的站点抓取到得信息，整合别的系统时，相互数据的迁移都要用到这些内容。我们建立一个简单的模型，只考虑节点基本数据，不考虑其他因素（比如节点图片，节点术语分类等等），将模型简单化有助于我们解决问题。</p>
<p>以拿抓取页面为例，我们使用正则表达式过滤出需要的信息后，将其存放在一个一维关联数组中，其中键对应数据库中的节点字段，比如title，body，name。。。然后我们手动调用node_submit方法，将一维数组传进去，这个方法会对我们的数组做一些存表之前的工作，我们直接可以在api.drupal.org查看这个方法的代码。</p>
<pre><code><span>&lt;?php
</span><span>function</span> <span><a title="Prepare node for save and allow modules to make changes." href="http://api.drupal.org/api/function/node_submit/5">node_submit</a></span>(<span>$node</span>) {
  <span>global</span> <span>$user</span>;

  <span>// Convert the node to an object, if necessary.
</span>  <span>$node</span> = <span>(object)</span><span>$node</span>;

  <span>// Auto-generate the teaser, but only if it hasn't been set (e.g. by a
</span>  <span>// module-provided 'teaser' form item).
</span>  <span>if</span> (!<span>isset</span>(<span>$node</span>-&gt;<span>teaser</span>)) {
    <span>$node</span>-&gt;<span>teaser</span> = <span>isset</span>(<span>$node</span>-&gt;<span>body</span>) ? <span><a title="Automatically generate a teaser for a node body." href="http://api.drupal.org/api/function/node_teaser/5">node_teaser</a></span>(<span>$node</span>-&gt;<span>body</span>, <span>isset</span>(<span>$node</span>-&gt;<span>format</span>) ? <span>$node</span>-&gt;<span>format</span> : <span>NULL</span>) : <span>''</span>;
  }

  <span>if</span> (<span><a title="Determine whether the user has a given privilege." href="http://api.drupal.org/api/function/user_access/5">user_access</a></span>(<span>'administer nodes'</span>)) {
    <span>// Populate the "authored by" field.
</span>    <span>if</span> (<span>$account</span> = <span><a title="Fetch a user object." href="http://api.drupal.org/api/function/user_load/5">user_load</a></span>(<span>array</span>(<span>'name'</span> =&gt; <span>$node</span>-&gt;<span>name</span>))) {
      <span>$node</span>-&gt;<span>uid</span> = <span>$account</span>-&gt;<span>uid</span>;
    }
    <span>else</span> {
      <span>$node</span>-&gt;<span>uid</span> = <span>0</span>;
    }
  }

  <span>$node</span>-&gt;<span>created</span> = !<span>empty</span>(<span>$node</span>-&gt;<span>date</span>) ? <span>strtotime</span>(<span>$node</span>-&gt;<span>date</span>) : <span>time</span>();

  <span>// Do node-type-specific validation checks.
</span>  <span><a title="Invoke a node hook." href="http://api.drupal.org/api/function/node_invoke/5">node_invoke</a></span>(<span>$node</span>, <span>'submit'</span>);
  <span><a title="Invoke a hook_nodeapi() operation in all modules." href="http://api.drupal.org/api/function/node_invoke_nodeapi/5">node_invoke_nodeapi</a></span>(<span>$node</span>, <span>'submit'</span>);

  <span>$node</span>-&gt;<span>validated</span> = <span>TRUE</span>;

  <span>return</span> <span>$node</span>;
}
<span>?&gt;</span></code></pre>
<p>除了一些数据的可用性检查外，该方法调用了所有实现submit和nodeapi中实现submit的函数，之后就简单了，再调用node_save即可。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/drupal-colletion-info.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>剖析ubercart</title>
		<link>http://www.terrysco.com/node/drupal-ubercart.html</link>
		<comments>http://www.terrysco.com/node/drupal-ubercart.html#comments</comments>
		<pubDate>Tue, 04 Aug 2009 10:25:05 +0000</pubDate>
		<dc:creator>terrysco</dc:creator>
				<category><![CDATA[CMS/FrameWork]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.terrysco.com/?p=240</guid>
		<description><![CDATA[ubercart是一套很好的搭建电子商务平台代码，被很好的以模块形式应用到了drupal上，接合drupal的强大功能很容易生成电子商务站点。 下载了最新版本的模块看了看，代码量确实巨大。要先学会怎么用，再去看代码我想工作效率会更高，所以启用模块建了几个产品试试，购物车和付费平台什么的功能都走通了之后开始挑几个重要的代码段看了看。因为我要实现一个充值后增加userpoints积分的功能，找了半天终于找到一个相关模块，但是问题很多，issue页面也有人提出了类似的问题。没办法只能靠自己了，了解product模块和feature相关特性后，很轻松的就找到了问题所在。大家需要类似功能的可以参考下。 http://drupal.org/node/514534 解决办法在评论里面，不过我没有测试，只是看到代码流程没有问题了。首先建立一个feature，将产品节点绑定到这个feature里面，再实现order这个hook，在里面判断当订单完成状态后，使用userpoints模块的接口给购买用户增加分数。至于points的分类和数目完全可以自己在后台设置，还是不错的功能，只是纳闷作者为什么这么粗心，错了一个变量，错了一个表名。]]></description>
			<content:encoded><![CDATA[<p>ubercart是一套很好的搭建电子商务平台代码，被很好的以模块形式应用到了drupal上，接合drupal的强大功能很容易生成电子商务站点。</p>
<p>下载了最新版本的模块看了看，代码量确实巨大。要先学会怎么用，再去看代码我想工作效率会更高，所以启用模块建了几个产品试试，购物车和付费平台什么的功能都走通了之后开始挑几个重要的代码段看了看。因为我要实现一个充值后增加userpoints积分的功能，找了半天终于找到一个相关模块，但是问题很多，issue页面也有人提出了类似的问题。没办法只能靠自己了，了解product模块和feature相关特性后，很轻松的就找到了问题所在。大家需要类似功能的可以参考下。</p>
<p>http://drupal.org/node/514534</p>
<p>解决办法在评论里面，不过我没有测试，只是看到代码流程没有问题了。首先建立一个feature，将产品节点绑定到这个feature里面，再实现order这个hook，在里面判断当订单完成状态后，使用userpoints模块的接口给购买用户增加分数。至于points的分类和数目完全可以自己在后台设置，还是不错的功能，只是纳闷作者为什么这么粗心，错了一个变量，错了一个表名。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.terrysco.com/node/drupal-ubercart.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

