文档索引 » QeePHP 快速入门 » 实现任务管理 » 修改和删除任务

修改和删除任务

修改工作非常简单,在 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;
}

这个方法完成下列工作:

  1. 首先根据指定的 task_id 和当前用户ID查询任务对象,如果失败则重定向浏览器。这可以有效阻止用户尝试编辑不属于自己的任务。
  2. 如果是 POST 提交,则更新任务信息,并且根据是否选中了“已完成”检查框来修改任务状态。最后保存修改并重定向浏览器。

上述代码中,之所以修改任务状态必须调用 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?