修改工作非常简单,在 tasks 控制器中添加如下代码即可:
function actionEdit() { $user=$this->_app->currentUserObject(); // 查询指定 ID,并且其所有者是当前用户的任务(禁止修改他人的任务),注意getOne会一直返回Task对象,如果不存在会返回新的Task对象 $task=Task::find('task_id =? and owner_id =?',request('task_id'),$user->id())->getOne(); // 如果任务的不存在,视图修改的任务不存在或者不是当前用户创建的 if ($task->isNewRecord()){ return $this->_redirectMessage('对不起', '任务不存在或已被删除', url('tasks/index')); } if (request_is_post()){ // 直接通过表单赋值 $task->changeProps($_POST); // 根据是否选中“已完成”检查框来设置任务的状态 $task->completed(request('is_completed',false)); // 保存并重定向浏览器 $task->save(); return $this->_redirect(url('tasks/index')); } $this->_view['task']=$task; }
这个方法完成下列工作:
上述代码中,之所以修改任务状态必须调用 completed() 方法,是为了因为 task 模型的 is_completed 属性非常重要,不应该“无意”中被修改。明确的 completed() 方法调用就可以避免此问题。而且当任务状态改变为“已完成”时,还需要设置任务的 completed_at 属性,以记录任务完成的时刻,completed() 方法可以同时完成这项修改。
所以我们还要在 task 模型中添加 completed() 方法:
/** * 明确修改任务的状态 * @param boolean $completed * @return Task */ function completed($completed){ $completed = (bool)$completed; if ($completed && !$this->is_completed) { // 如果任务状态从“未完成”变成“已完成”,则保存完成任务的时刻 // changePropForce() 可以强制改变一个只读属性的值 $this->changePropForce('completed_at', time()); } elseif (!$completed) { // 如果任务状态设置为“未完成”,则清理掉 completed_at 记录的时间 $this->changePropForce('completed_at', null); } $this->changePropForce('is_completed', $completed); return $this; }
同时修改 _code/view/tasks/edit.php
<?PHP $this->_extends('_layouts/default_layout'); ?> <?PHP $this->_block('contents');?> <div> <form action="" method="post"> <input type="hidden" name="task_id" value="<?php echo $task->id()?>"> <?php if (!empty($errors)):?> <div class="alert"> <?php echo $errors?> </div> <?php endif;?> <fieldset> <legend>编辑任务 - <?php echo $task->id()?></legend> <p> <label>任务主题</label> <input name="subject" value="<?php echo $task->subject?>"> </p> <p> <label>任务描述</label> <textarea name="description" style="width:400px;height: 100px;"><?php echo $task->description?></textarea> </p> <p> <label> <input type="checkbox" name="is_completed" value="1"> 完成 </label> </p> <p> <input type="submit" value="提交"> </p> </fieldset> </form> </div> <?PHP $this->_endblock();?>
相比传统的做法,面向对象的方式在初期会需要更多的代码。但是这些代码保证了逻辑的严密性和数据的有效性,应用软件规模越大,这种做法带来的好处就越多。而且随着应用规模的逐渐增长,面向对象充分重用逻辑与代码的优势就会体现出来,最终可以获得一个更健壮、内部更整洁的系统。
实际运行效果:
修改状态后的任务
删除任务功能非常简单:
function actionDelete() { // destroyWhere() 方法的参数和 find() 方法完全一致 $user=$this->_app->currentUserObject(); Task::meta()->destroyWhere('task_id = ? AND [owner.user_id] = ?',request('task_id'),$user->id()); return $this->_redirectMessage( '删除成功', '您已经成功删除了一个任务', url('tasks/index') ); }
修改一下 _code/view/tasks/index.php 视图,将删除任务的连接加进去:
<p class="meta"> <?php if ($task->is_completed): ?> <em>已经在 <?php echo date('m-d H:i', $task->completed_at); ?> 完成该任务</em> <?php else: ?> <strong>添加日期:<?php echo date('m-d H:i', $task->created); ?></strong> <?php endif; ?> , <a href="<?php echo url('tasks/delete', array('task_id' => $task->id())); ?>" onclick="return confirm('您确定要删除该任务吗?');">删除</a> </p>
运行效果:
删除提示
成功删除
课后思考:大家不难发现,创建任务和编辑任务的View代码相差不大,重用性非常高,是否有好的办法可以将两个View合并为一个View?设置两个Action合并为一个Action?