forecho 的独立博客

把生命浪费在美好的事物上

CakePHP Ajax分页

2014年01月23日

Controller文件头部调用CakePHP自带分页并且配置分页条数代码:

public $components = array('RequestHandler', 'Paginator');
public $paginate = array('limit' => 2 );  //2是为了方便测试

调用的action方法如下:

public function list()
{
    $this->Paginator->settings = $this->paginate;
    $data = $this->Paginator->paginate('Notice');
    $this->set('data', $data);
}

list.ctp文件,代码如下:

<?php echo $this->Js->writeBuffer(array('inline'=>false));?>
<div id="search_result">
    <?php foreach ($data as $key => $value): ?>
        <?php echo $value['Notice']['title'] ?>
    <?php endforeach ?>
    <?php $this->Paginator->options(array(
                'update' => '#search_result',
                'evalScripts' => true,
    ));?>
    <?php echo $this->Paginator->prev('上一页' . __('', true), array(), null, array('class'=>'disabled'));?>
    <?php echo $this->Paginator->numbers(array('class' => 'numbers', 'first' => false, 'last' => false));?>
    <?php echo $this->Paginator->next(__('下一页', true) . ' >>', array(), null, array('class' => 'disabled'));?>
    <?php echo $this->Js->writeBuffer(array('inline'=>true));?>
</div>

参考文章: http://endoyuta.com/2013/05/06/cakephp-2-3-ajax%E3%81%AApagination/ http://caky.de/en/core-libraries/helpers/js.html#ajax-pagination

Yii扩展自带的时间选择器插件CJuiDatePicker

2014年01月13日

事情大概是这样的:我数据库时间字段用的是 int 类型,存储的是时间戳。并且我写文章的时候,时间是需要可以修改的。

来一张最终效果图:

首先我用了 Yii 自带的 Zii CJuiDatePicker 扩展,非常的强大的把 jQuery UI 的 Datepicker 继承进去了,使用非常的简单,手册上有。但是这个有个缺陷,没有小时分钟,只能配置日期。这个有点坑爹了。然后没办法,去找了一个 yii 的扩展。我选了 ejuidatetimepicker,使用也很简单,基本就按照给的 Demo复制过去就可以了。

现在来说说这个功能的难点,首先我数据库是 int 时间戳格式的,但是我用的这个插件是日期格式的,那么现在我又不想改数据库时间的字段类型,我要如何解决? Google 了一下,找到了一篇文章,我按照这个来结果成功了。

首先根据插件的 Demo 我们在视图form的时间是这样写的:

<?php echo $form->labelEx($model,'create_time'); ?>
    <?php $this->widget('application.extensions.timepicker.EJuiDateTimePicker',array(
        'model'=>$model,
        'attribute'=>'create_time',
        'language'=>'zh-CN',
        'options'=>array(
            'hourGrid' => 4,
            'hourMin' => 9,
            'hourMax' => 17,
            'timeFormat' => 'hh:mm',
            'changeMonth' => true,
            'changeYear' => false,
            ),
        'htmlOptions'=>array(
            'readonly'=>true,
            'style'=>'width:180px;'
        ),
    )); ?>
<?php echo $form->error($model,'create_time'); ?>

控制器部分我们基本上不用修改。接下来我们去修改 Model 文件,添加两个 yii 的 function:

protected function beforeSave()
{
    $this->admin_id = Yii::app()->user->id;
    // $this->create_time = date('Y-m-d', CDateTimeParser::parse($this->create_time, 'yyyy-MM-dd hh:mm'));
    $this->create_time = strtotime($this->create_time);
    return parent::beforeSave();
}

protected function afterFind()
{
    $this->create_time = Yii::app()->dateFormatter->format('yyyy-MM-dd hh:mm', $this->create_time);
    return parent::afterFind();
}

beforeSave 就是数据保存之前我们要处理的事件。afterFind 就是数据显示之前我们要处理的事件。 非常巧妙的用法。

最后别忘记了把 Model 的 rules 的时间验证规则改一下,代码如下:

array('create_time', 'date', 'format'=>'yyyy-MM-dd hh:mm', 'message'=>'{attribute} have wrong format'),

**值得注意的是 rules 验证会在 beforeSave 之前执行。beforeSave 和 afterFind 都是 protected 属性。

** 参考文章:** - http://www.yiiframework.com/extension/ejuidatetimepicker/ - http://www.yiiframework.com/doc/api/1.1/CJuiDatePicker - http://www.volkomenjuist.nl/blog/2013/02/24/yii-cjuidatepicker-dateformat/   

最后感叹下自带 zii 的方便强大,再分享一个资源: http://www.bsourcecode.com/yii-framework/yii-extensions/

Comments

Jack Van: 怎么只能从9点到16点

ForEcho: 代码上面有参数。自己可以设置,hourMin 和 hourMax

CakePHP的小技巧用法

2014年01月03日

1、问:如果控制器有一个方法,不要视图怎么办?

答:使用:$this->autoRender = false

2、对于一直在开发的网站,在频繁更新的情况下,如何保证css文件、js文件和image文件不调用浏览器缓存文件问题?

答:一个是在调用的文件名最后加变量后缀,如时间。示例代码如下:

<link rel="stylesheet" type="text/css" href="http://forecho.com/css/index.css?2014-01-03-1" media="all" />

二如果是CakePHP的话还可以修改core.php配置文件,代码如下:

/**
 * Apply timestamps with the last modified time to static assets (js, css, images).
 * Will append a querystring parameter containing the time the file was modified. This is
 * useful for invalidating browser caches.
 *
 * Set to `true` to apply timestamps when debug > 0. Set to 'force' to always enable
 * timestamping regardless of debug value.
 */
    Configure::write('Asset.timestamp', true);

这样的好处是你接下来可以直接用CakePHP自带的写法调用图片和文件了,如:

<?php
	echo $this->Html->css('main');
	echo $this->Html->image();
?>

3、点赞的时候需要+1,如何更新数据库?

代码如下:

$this->Widget->updateAll(
    array('Widget.numberfield' => 'Widget.numberfield + 1'),
    array('Widget.id' => 1)
);

4、如何通过主键最简单的方式获取到一条数据?

代码如下:

// 只获取name字段信息
$this->User->read("name", $id);
// 获取所有信息
$this->User->read(null, $id);

5、CakePHP控制器如何返回上一页?

$this->redirect($this->referer());

6、CakePHP A控制器调用B控制器

$this->requestAction(
    array('controller'=>'Wx','action'=>'aa'),
    array('data'=>
        array('xing'=>'A1','ming'=>'A2')
    )
);

这样可以在A控制器调用B控制器方法,而且在后面传参过去,用$this->request->data获取参数值。

7、输出单个页面执行的SQL语句

$log = $this->Model->getDataSource()->getLog(false, false);
debug($log);

Model要改一下名字才能用。

庆「元旦」读完《淘宝技术这十年》

2014年01月01日

元旦放假一天,天气不错无处可玩,想着去广场晒着太阳应该是件很不错的事情。于是吃完午饭抱着同事借来的《淘宝技术这十年》去广场找了个位置看书,在家对着电脑不管多安静,我是看不进去书的。 其实以前在博客园的这里已经看得差不多一半了,其实书的内容不怎么多的,除了讲技术的部分不明觉厉之外,其他的章节还是很有意思的。下面就摘抄一些有意义的笔记。内容主要为后面一章节,本书的前一半内容看的比较早了,当时忘记记录笔记了。

子柳:你对刚入行的技术人员有什么建议?
正明:找到自己感兴趣的,花时间投进去,通过实践后的知 识积累比只看书本有用得多。我看过一本操作系统方面的英文书,其中引用了一段中国人的格言:“I hear and I forget. I see and I remember. I do and I understand”,这句话给我留下非常深刻的 印象。是荀子说的“不闻不若闻之,闻之不若见之,见之不若知 之,知之不若行之。”

子柳:从你的经历来看,你对现在的技术人员的成长有什么建议?
正祥:很多人会说年轻人比较浮躁,其实我的身边有很多非常优秀的年轻人,他们聪明、刻苦、有闯劲、愿意接受新事物。 年轻的同事想赚钱,想提升自己的职称,这些都是十分正常的。 在这点上,我特别喜欢马总的理念——做公司要赚钱,但阿里从 不把赚钱作为第一目标,我们服务好了客户,客户赚了钱,我 们一定会得到自己应得的一份。在个人成长问题上也是类似的 道理,这就是,一个人如果把做事、做成事作为主要目标,该他 得到的东西,一定会顺理成章的、水到渠成地得到,但是,如果 把上升作为主要目标,做同样的事,结果就会完全不一样。一句 话,你的心态会最终决定你的成就。

子柳:你来淘宝技术大学授课的时候,给学员说过“但行好 事,不问前程”,现在很多同学都因为晋升的问题很纠结,可否 解释一下自己是怎么看待晋升的?
毕玄:大家都说了,晋升是一个“水到渠成”的事情。大家 都会在意晋升,这个是正常的,除非你不在意级别,生活上也没 有压力,不过这样的人是很少的,呵呵。如果真的没有升上去, 这个也没有什么办法能够挽救了。我觉得重要的是在这个过程中 你回顾了你一年做了什么事情,对公司有什么贡献,技术上有哪些成长。 对于技术人员最常见的一种情况是晋升名单公布的时候,你 去看谁升上去了,然后对比一下自己,觉得他水平不如自己,为 什么是他得到了晋升,而不是你。我觉得最重要的是看那个人对 公司做了多少贡献,你可以说你的技术确实很强,但事实是你对 公司没有做出任何贡献。

子柳:你是技术晋升的评委,在评审的过程中,你比较看重什么样的特质?
毕玄:如果你是向技术方向发展的人员,我们要看技术方面的专业性;然后看你的技术对公司的业务发展有多少贡献。还有 一点,我比较看重的是,也许你不在其位,但能够跳出自己的范 围,想到公司未来到底会面临什么问题,用什么方法来解决。当 然,仅想是不够的,如果你能够落实就最好了,我们不管你落实 的技术含量有多高,关键是你解决了什么样的问题。如果你能够 做到这些,你这个人对公司就非常重要。

子柳:你经常出去招聘学生,你欣赏什么样的学生?
毕玄:其实在校招聘的时候,我比较欣赏的学生往往是那些很“不务正业”类型的。我经常会问他们,你有没有利用业余时间出于自己的技术兴趣做的一些小东西。这样的学生我们通常 会比较感兴趣,我认为这样的学生是真正喜欢技术。聪明程度一般就可以的,他能够进入这些不错的学校,智商是不会有什么问 题的。

子柳:你对新人的要求是什么样的?
放翁:第一个是做事要自己思考后再去问别人,而不是一遇到问题就找人求助。第二个是不断地打破自己的一些想法,你不要担心自己今天已经做了50%的工作,要是推倒重来,前面的事情都白干了。我现在带的两个新人成长很快,但是都有类似的经历,就是一个东西被我反复推翻重做,在这个过程中就是不断地成长,要思考我为什么让你推倒重做,若想不清楚,下次重做的概率会更大,这样慢慢地就会学会了思考。

子柳:你对工程师有什么忠告?
放翁:任何一个公司,不管用什么手段,都做不到绝对公 平,最终只会有小部分人得到机会。这个时候去抱怨、愤怒都没 有用的,只有自己不断地努力争取机会才行。

子柳:给技术刚起步的人员一些技术成长的建议吧。
云铮:兴趣是最好的老师,坚持是达到梦想的唯一途径,当然,在个人发展的不同阶段寻找到合适的导师很重要,看准方向 会事半功倍。在刚刚参加工作还没有形成自己的判断时,方向有 两个来源,一个是个人的兴趣,一个是找一个你非常佩服且能掌 握未来方向的人,当然,如果这两者正好重合,那么剩下的就是 脚踏实地坚持。

子柳:说说你个人的成长经验,给起步阶段的同事一些建议吧。
小马:现在回过头来看,其实成长最快的一段时间是刚进淘 宝的那几年,那个时候很单纯,就想着把工作做好,做完一个做 下一个,不管这个业务是不是重要,需求方是不是好打交道。有个“一万个小时理论”,我觉得很正确,说的就是一个人必须经 过不断地练习,不断地遇到问题才能成长起来。当然,做的时候 要不断总结,写博客是一个很好的途径。

子柳:现在有很多人出去创业,作为一个曾经创过业的技术 人员,你有什么看法?
小马:很多人创业是因为公司变得越来越大,有很多流程和 规章制度的限制,这样自己发挥的空间越来越小。但是真的到 社会中创业时会发现限制同样很多,你同样要面临税务局、工商 局、商标、公司注册、股东关系、员工管理、同行竞争等问题, 这跟你在公司中工作并没有本质的不同。所以说创业其实是一种 心态,你用旺盛的精力、饱满的斗志和坚定的信念去克服一个又 一个的困难,这就是创业。到外面去创业和在一个大公司里创 业,我个人觉得并没有本质的区别。 当然,如果你不认可公司整体的方向,或者你不认可这个行 业,你有一个理想去打造一个新的天地,公司也应该有这种胸怀 鼓励你去创业。

总结一下去年真正看完的书只有可怜的《Getting Real – 37signals》、《不许联想》、《打造 Facebook》、《把时间当作朋友》4本。太少了,争取今年能至少读完10本书。

CakePHP saveAll用法

2013年12月26日

视图表单代码如下:

<tr id="research-items">
	<td>
		<select name="type[]">
			<option value="text">单行文字</option>
			<option value="textarea">多行文字</option>
			<option value="radio">单项选择</option>
			<option value="checkbox">多项选择</option>
		</select>
	</td>
	<td><input type="text" name="question[]" value="" placeholder="这里是问题"></td>
	<td><input type="text" name="items[]" value="" placeholder="答案1|答案2"></td>
	<td>
		<input type="checkbox" name="is_answer[]" value="1" <?php echo (isset($data) && $data['ResearchSetting']['is_answer']==1) ? "checked" : '' ; ?>>是否必填
	</td>
	<td><a class="btn_delete" title="删除" href="javascript:;">删除</a></td>
</tr>

控制器的写法如下:

for ($i=0; $i < count($_POST['type']) ; $i++) {
     $post[$i]['ResearchOption']['type']                = $_POST['type'][$i];
     $post[$i]['ResearchOption']['question']            = $_POST['question'][$i];
     $post[$i]['ResearchOption']['items']               = $_POST['items'][$i];
     $post[$i]['ResearchOption']['is_answer']           = ($_POST['is_answer'][$i])?$_POST['is_answer'][$i]:0;
     $post[$i]['ResearchOption']['research_setting_id'] = $this->ResearchSetting->id;
}
$this->ResearchOption->saveAll($post);

参考链接:http://book.cakephp.org/2.0/en/models/saving-your-data.html

CakePHP hanMany用法

2013年12月18日

hanMany就是一对多的关系,比方说我们现在一篇文章有多条评论,那么这个就是一对多的关系。 我们在文章的模型里面写hasMany就可以关联评论了。使用方法如下:

var $hasMany = array('ProductsSku' =>
		array('className'     => 'ProductsSku',//关联对象类名
				'conditions'    => '',//关联对象限定条件
				'order'         => '',//关联对象排序子句
				'limit'         => '',//检索的关联对象数量
				'foreignKey'    => 'prod_id',//外键字段名
				'dependent'     => true,//是否级联删除
				'exclusive'     => false,//:如果设为true,所有的关联对象将在一句sql中删除,model的beforeDelete回调函数不会被执行。但是如果没有复杂的逻辑在级联删除中,这样的设定会带来性能上的优势。(译注:Cake的确方便,但是使用时一定要记住控制sql语句发送数量)
				'finderQuery'   => ''//定义一句完整的sql语句来检索关联对象,能够对关联规则进行最大程度上的控制。当关联关系特别复杂的时候,比如one table - many model one model - many table的情况下,Cake无法准确的替你完成映射动作,需要你自己来完成这个艰巨的任务。
		)
);

在CakePHP命名规范里面规定每一张表都有ID为主键的字段,作为外键foreignKey的字段命名:其默认值为当前模型的单数模型名缀以 ‘_id’。如果你遵守这个使用起来将非常简单。 下面我们来说个实例。 文章的表名为Articles,文章评论表名为Comments。那么文章的模型文件为Article.php,文章评论的模型文件为Comment.php。(单复数命名规则) 那么在Article.php文件中这样写就可以实现简单的关联评论表了。

class Article extends AppModel
{
    public $name = 'Article';

    public $hasMany = array(
        'Comment' => array(
            'className'  => 'Comment',
        )
    );
}

参考资料: http://www.cnblogs.com/matchless/archive/2013/02/01/2889134.html http://www.21haolou.com/articles/show/88

PHP jQuery JSON 二级联动

2013年12月12日

HTML代码如下:

<select name="category_f" id="category_f" class="valid">
    <option value="1">美食</option>
    <option value="2">休闲娱乐</option>
    <option value="3">其他</option>
</select>
<select name="category_s" id="category_s" class="valid">
	<option value="11">本帮江浙菜</option>
	<option value="12">川菜</option>
</select>

JavaScript代码如下:

<script type="text/javascript">		
    $("#category_f").click(function() {
        var html = '';
    	$.ajax({
    		url: '/getcategory', //PHP方法
    		type: 'POST',
            dataType: 'json',
    		data: {f: $(this).val()},
            success:function(msg){
                $.each(msg,function(key,val){
                    html += '<option value="' + key + '">' + val + '</option>';
                });
                $("#category_s").html(html);
            }
    	})
    });
</script>

 PHP action处理页面:

public function getcategory()
{
	$json[1]  = '{"11":"本帮江浙菜","12":"川菜"}';
	$json[2]  = '{"30":"密室","31":"咖啡厅","32":"酒吧"}';
	$json[3] = '{"136":"其他"}';

	exit($json[$_POST['f']]);
}

上面代码已经可以用了,但是修改页面如何去实现呢?所以我要重构上面的代码。 JavaScript代码被改成这样了(重在理解代码,我这个代码有可能在你的场景中不适用):

<script type="text/javascript">
    // 自动加载 用于修改时
    $(document).ready(function() {
        ajaxSelect(<?php echo ($data) ? $data['category_f'] : 1 ; ?>, <?php echo ($data) ? $data['category_s'] : 11 ; ?>);
    });
    // 手动修改 二级联动
    $("#category_f").click(function() {
        ajaxSelect($(this).val(), 11);
    });
    // 二级联动
    function ajaxSelect (argument,id) {
        var html = '';
        $.ajax({
            url: '/getcategory',  //PHP方法
            type: 'POST',
            dataType: 'json',
            data: {f: argument},
            success:function(msg){
                $.each(msg,function(key,val){
                    if(id == key) {
                        html += '<option value="' + key + '" selected>' + val + '</option>';
                    }else{
                        html += '<option value="' + key + '">' + val + '</option>';
                    }
                });
                $("#category_s").html(html);
            }
        })
    }
</script>

HTML简化后如下:

<select name="data[category_f]" id="category_f" class="valid">
     <option value="1" <?php if($data && $data["category_f"]==1) echo "selected"; ?>>美食</option>
     <option value="2" <?php if($data && $data["category_f"]==2) echo "selected"; ?>>休闲娱乐</option>
     <option value="3" <?php if($data && $data["category_f"]==3) echo "selected"; ?>>其他</option>
</select>
<select name="data[category_s]" id="category_s" class="valid"></select>

PHP action代码不变。

简单介绍 Rails 默认文件结构

2013年12月09日

文件/文件夹 说明

app/ 程序的核心文件,包含模型、视图、控制器和帮助方法

app/assets 程序的资源文件,如 CSS、JavaScript 和图片

bin/ 可执行文件

config/ 程序的设置

db/ 数据库文件

doc/ 程序的文档

lib/ 代码库文件

lib/assets 代码库包含的资源文件,如 CSS、JavaScript 和 图片

log/ 程序的日志文件

public/ 公共(例如浏览器)可访问的数据,如出错页面

script/rails 生成代码、打开终端会话或开启本地服务器的脚本

test/ 程序的测试文件(在 3.1.2 节 中换用 spec/

tmp/ 临时文件

vendor/ 第三方代码,如插件和 gem

vendor/assets 第三方代码包含的资源文件,如 CSS、JavaScript 和图片

README.rdoc 程序简介

Rakefile rake 命令包含的任务

Gemfile 该程序所需的 gem

Gemfile.lock 一个 gem 的列表,确保本程序的复制版使用相同版本的 gem

config.ru Rack 中间件的配置文件

.gitignore git 忽略的文件类型 来源:http://railstutorial-china.org/chapter1.html 参考资料:http://ruby-china.org/topics/2432

Git 分支的应用

2013年12月08日

创建分支( modify-README 为分支名):

$ git checkout -b modify-README

注:创建完之后默认切换到这个分区。 列出所有的分支:

$ git branch

 合并到主分区:

$ git checkout master
$ git merge modify-README

注:先切换到主分区,再合并。 删除分区:

$ git branch -d modify-README