CakePHP 2.x十分钟博客教程(三):数据库基础操作、表单、路由器

通过前面两篇文章的学习,你的CakePHP博客已经初具雏形了。本文会构建博客的文章内容页面,添加新的文章,修改老文章以及删除文章的功能,并且涉及到CakePHP表单创建,数据验证,路由规则等主题。如果还没有仔细了解本教程的前两张,可以访问《Cakephp 2.0十分钟博客教程(一):安装与配置》从头开始学习。

锐想网CakePHP系列教程—CakePHP博客三部曲:

文章内容页

在上一篇教程当中,我们已经实现了博客文章列表的显示,并且在文章名上包含该篇文章的URL地址。复习下该段代码。

01
02
03
04
echo $this->Html->link(
    $post[‘Post‘][‘title‘],
    array(‘controller‘ => ‘posts‘, ‘action‘ => ‘view‘, $post[‘Post‘][‘id‘])
);

该URL指向PostsController控制器的View方法,并传递文章的id作为URL参数。如果点击该链接,可以发现URL地址如下所示。

www.example.com/posts/view/id

现在,一起为该页面建立控制器。在PostsController控制器中添加view()方法,代码如下。

01
02
03
04
public function view($id = null) {
    $this->Post->id = $id;
    $this->set(‘post‘, $this->Post->read());
}

这段代码非常简单,通过参数获取到文章$id,然后赋予Post模型对象的id属性,接着通过该对象的read()方法读取匹配该id的一行数据, 并赋予post变量传递到视图文件中。完成控制器之后,该为文章内容页建立视图文件了,view视图文件路径位于/app/View/Posts /view.ctp。创建该文件,并复制如下代码到该文件中。

01
02
03
04
05
<!-- 路径: /app/View/Posts/view.ctp -->
 
<h1><?php echo $post[‘Post‘][‘title‘]?></h1>
<p><small>Created: <?php echo $post[‘Post‘][‘created‘]?></small></p>
<p><?php echo $post[‘Post‘][‘body‘]?></p>

完成上述操作之后,访问index页面,点击文章标题,即可访问view页面。一切正常的话,CakePHP会使用默认布局文件显示如下内容。

添加文章 — CakePHP表单助手

显示文章列表以及文章内容是一个好的开始,然而一个简单的CakePHP博客应用必不可少的就是添加新的文章。这次改变下文件创建的顺序,我们首先 创建视图文件,来构建博客页面添加文章的表单。事先约定,在PostsController控制器中处理文章添加逻辑的方法为add(),那么相应的模板 文件就位于/app/View/Posts/add.ctp。

之前我们说到CakePHP视图层包含许多助手类,其中就有一个FormHelper用于输出HTML表单。将如下代码复制到add.ctp视图文件中。

01
02
03
04
05
06
07
<h1>Add Post</h1>
<?php
    echo $this->Form->create(‘Post‘);
    echo $this->Form->input(‘title‘);
    echo $this->Form->input(‘body‘, array(‘rows‘ => ‘3‘));
    echo $this->Form->end(‘添加‘);
?>

表单助手类默认可以在任何视图文件中调用,通过$this->Form,即可实例化一个新的FormHelper类对象。上述代码首先通过create()方法,生成了表单头,如下所示,

<form id=”PostAddForm” method=”post” action=”/posts/add”>

在上面的create()方法中,我们传递了Post作为参数,该参数用于指定当前模型名。默认的,如果该方法没有传递任何参数,则假设该表单通过Post方式,默认当前模型,传递表单数据到当前控制器的add()方法中进行处理。

input()方法用于input表单元素。参数一用户匹配数据库的字段,参数二用于指定该表单元素的各种设置,以索引数组形式组织。

end()方法用于生成表单提交按钮,并完成表单HTML代码的结尾部分。该方法如果指定参数,则用于表单提交按钮中的按钮文字。

到此为止,我们的视图文件建立完毕。是时候建立控制器方法处理该表单提交的数据了。在PostsController控制器中添加一个add()方法,并添加如下代码到该方法中。另外需要在控制器中新建一个$components属性,该属性的作用稍后会作解释。

01
02
03
04
05
06
07
08
09
10
11
12
public $components = array(‘Session‘);
 
public function add() {
    if($this->request->is(‘post‘) {
        if($this->Post->save(($this->request->data)) {
            $this->Session->setFlash(‘新文章创建完成‘):
            $this->redirect(array(‘action‘ => ‘index‘));
        } else {
            $this->Session->setFlash(‘创建文章出错‘);
        }
    }
}

完成上述代码之后,访问www.example.com/posts/add,会显示如下页面。

add()方法是目前PostsController控制器中最复杂的方法了。首先,通过$this->request获取 CakeRequest请求对象,然后判断当前HTTP请求是否为POST类型。还记得吧,上面创建的表单默认是通过POST方式传递数据的,如果是, 则$this->Post获取到模型对象,并调用起save()方法保存表单提交来的数据到数据库中。

需要注意的是$this->request->data,上面说到request是获取到了框架封装的CakeRequest类对象, 接着获取其data属性中的值。这里实际上就是表单中提交的数据。可以通过CakePHP调试方法pr()输出下该数组,查看该数组的结构。

接着用到了新添加的Session组件,该组件用于设置一段消息并保存在session变量中,该段消息可以在页面转向后显示在视图文件中。相对于 控制器中SessionComponent::setFlash()方法设置的字符串消息,在转向后的视图文件中,可以通过 SessionHelper::flash()方法显示该消息,显示结束后,系统会自动销毁该变量,再次刷新页面,就不会再次显示该消息。

写好session消息之后,保存成功,页面需要转向到博客的文章列表页,该步骤通过控制器的流程控制方法redirect()进行,该方法同样使 用数组形式作为URL地址,上述代码中意思是转向到当前控制器Posts的index()方法。如果想了解更多的关于CakePHP框架的URL组成形 式,可以查看Router::url()方法。

到此为止,如果一切正常的话,你应该可以完美添加新的博客了,如下图所示,填写表单并点击提交之后,系统会转向的文章列表页,注意,红色背景显示的 文字即我们在控制器中通过SessionComponent::setFlash()方法设置的提示成功的消息,如果再次刷新页面,该消息会自动消失。

CakePHP 表单数据验证

CakePHP模型类中可以通过$validate属性定义表字段的验证规则,该验证规则主要面向用户通过表单提交的数据。在上面的代码中我们通过 FormHelper助手类生成了表单代码,如果说在该表单页面中不填写数据直接提交,也可以通过。而这并不是我们想要的结果,一篇博客文章,至少应该包 含文章标题和文章内容。

这些验证规则可以通过在相应的模型中的$validate属性进行定义,进入/app/Model/Post.php文件,添加如下代码到Post模型类中。

01
02
03
04
05
06
07
08
public $validate = array(
    ‘title‘ => array(
        ‘rule‘ => ‘notEmpty‘
    ),
    ‘body‘ => array(
        ‘rule‘ => ‘notEmpty‘
    )
);

$validate属性通过上述数组形式进行赋值,根据数据库字段,非常容易该段代码的含义。这里,我们制定‘title’和’body’字段的验 证规则为非空(notEmpty)。完成该段代码之后,访问add()访问,提交一个空的或者任意表单域为空的时候,系统会出现禁止提交的提示,如下图所 示。

CakePHP的验证系统非常强大,本身内置了如信用卡号,email地址等规则,你也可以自己建立新的验证规则,以适用不同的数据。访问Data Validation获得更多数据验证的信息。另外,CakePHP表单之所以能够关联模型中字段的验证规则,大前提是通过FormHelper表单助手来创建表单元素,如果你是通过HTML标签进行编码,则无法享受CakePHP框架的表单验证功能。

编辑博客

细心的同学可以发现,锐想CakePHP基础教程到目前为止,为大家提供的例子都遵循了一个基本顺序。建立控制器方法,接着再写视图文件(除了表单一节,为了方便大家学习,首先写出的包含表单的视图文件)。接下来,我们继续按照该顺序构建博客的编辑逻辑。

在PostsController控制器中创建edit()方法,赋值如下内容到该方法。

01
02
03
04
05
06
07
08
09
10
11
12
13
function edit($id = null) {
    $this->Post->id = $id;
    if ($this->request->is(‘get‘)) {
        $this->request->data = $this->Post->read();
    } else {
        if ($this->Post->save($this->request->data)) {
            $this->Session->setFlash(‘Your post has been updated.‘);
            $this->redirect(array(‘action‘ => ‘index‘));
        } else {
            $this->Session->setFlash(‘Unable to update your post.‘);
        }
    }
}

在看上述代码之前,我们需要回忆下大家在编辑老文章时候的顺序。首先你看到的依然是文章列表,然后在文章列表中选择文章进行编辑。

代码中,首先通过URL传递来的参数获取到文章的id。先判断请求是否为GET方式,如果是GET请求,说明是在文章列表页点击编辑链接,此时,我 们需要读取该id相对应的数据,然后赋予request对象的data属性,以在视图文件中的表单域显示,方便我们进行修改。接着,else体重,当我们 修改完成,点击提交时,该请求一定是POST方式进行。这段代码和save()方法完全一致,不再多做解释。

view()方法相对应的视图文件如下。

01
02
03
04
05
06
07
08
09
<!-- File: /app/View/Posts/edit.ctp -->
 
<h1>Edit Post</h1>
<?php
    echo $this->Form->create(‘Post‘, array(‘action‘ => ‘edit‘));
    echo $this->Form->input(‘title‘);
    echo $this->Form->input(‘body‘, array(‘rows‘ => ‘3‘));
    echo $this->Form->input(‘id‘, array(‘type‘ => ‘hidden‘));
    echo $this->Form->end(‘Save Post‘);

该视图文件与add()方法的视图文件也没有太大区别,唯一多出的是一个隐藏表单,和使用HTML标签写表单时隐藏域的功能一样,它负责在点击提交按钮时,传递当前编辑的文章id值。另外,添加新的文章与编辑文章的控制器代码实在相似,CakePHP是如何区分两种操作的呢?方法是$id,如果在request对象中的data元素中包含id键,则判定为更新博客;如果没有id值,则判定为添加新博客。

PS:值得注意的是,在进入文章编辑页面时,表单中会显示该条数据到相应的表单字段中。可能大家会想,可以通 过$this->Post->read()获取数据,然后赋予一个变量,并以表单value属性值的形式,传递到视图文件中,以实现表单域中 显示待编辑内容的效果。但是CakePHP框架已经为我们准备好了一切,我们只需要将值取出后赋予request对象的data属性即可,不需要再多写一 行代码。

接着,可以在index.ctp视图中为每一篇文章添加一个修改按钮了。赋值如下内容到之前创建的index.ctp文件中。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- 文件路径: /app/View/Posts/index.ctp  (添加编辑URL) -->
 
<h1>Blog posts</h1>
    <p><?php echo $this->Html->link("Add Post", array(‘action‘ => ‘add‘)); ?></p>
    <table>
        <tr>
            <th>Id</th>
            <th>Title</th>
            <th>Action</th>
            <th>Created</th>
        </tr>
 
<!-- 循环输出由控制器中赋值的$posts变量 -->
 
        <?php foreach ($posts as $post): ?>
        <tr>
            <td><?php echo $post[‘Post‘][‘id‘]; ?></td>
            <td>
                <?php echo $this->Html->link($post[‘Post‘][‘title‘], array(‘action‘ => ‘view‘, $post[‘Post‘][‘id‘]));?>
            </td>
            <td>
                <?php echo $this->Html->link(‘Edit‘, array(‘action‘ => ‘edit‘, $post[‘Post‘][‘id‘]));?>
            </td>
            <td>
                <?php echo $post[‘Post‘][‘created‘]; ?>
            </td>
        </tr>
        <?php endforeach; ?>
    </table>

删除文章

关于CakePHP数据库的操作进行到了最后一步,删除文章也是博客应用中必不可少的环节。在PostsController控制器中创建delete()方法。

01
02
03
04
05
06
07
08
09
function delete($id) {
    if ($this->request->is(‘get‘)) {
        throw new MethodNotAllowedException();
    }
    if ($this->Post->delete($id)) {
        $this->Session->setFlash(‘The post with id: ‘ . $id . ‘ has been deleted.‘);
        $this->redirect(array(‘action‘ => ‘index‘));
    }
}

delete()方法包含$id参数,该参数用于表示文章,匹配数据库表中的递增id字段,第一个if语句用于判断当前请求的类型,在后边的视图文 件中我们会看到,删除操作是通过表单助手的postLink()方法完成的,所以说如果检测到当前请求是GET形式,则很有可能网站遭到了某种黑客攻击或 者误操作。

确定没有问题之后,通过Post模型对象的delete方法,即可删除该条数据。非常简单,不是嘛。最后,在index.ctp文章列表视图中,在每条博客后边添加 一个删除博客的链接按钮。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!-- 文件: /app/View/Posts/index.ctp -->
 
<h1>Blog posts</h1>
<p><?php echo $this->Html->link(‘Add Post‘, array(‘action‘ => ‘add‘)); ?></p>
<table>
    <tr>
        <th>Id</th>
        <th>Title</th>
                <th>Actions</th>
        <th>Created</th>
    </tr>
 
<!-- Here‘s where we loop through our $posts array, printing out post info -->
 
    <?php foreach ($posts as $post): ?>
    <tr>
        <td><?php echo $post[‘Post‘][‘id‘]; ?></td>
        <td>
            <?php echo $this->Html->link($post[‘Post‘][‘title‘], array(‘action‘ => ‘view‘, $post[‘Post‘][‘id‘]));?>
        </td>
        <td>
            <?php echo $this->Form->postLink(
                ‘Delete‘,
                array(‘action‘ => ‘delete‘, $post[‘Post‘][‘id‘]),
                array(‘confirm‘ => ‘Are you sure?‘));
            ?>
            <?php echo $this->Html->link(‘Edit‘, array(‘action‘ => ‘edit‘, $post[‘Post‘][‘id‘]));?>
        </td>
        <td>
            <?php echo $post[‘Post‘][‘created‘]; ?>
        </td>
    </tr>
    <?php endforeach; ?>
 
</table>

上述视图文件没有太多值得解释的地方。唯一需要注意的是postLink()方法。该方法在表单助手中定义,使用Javascript创建POST请求完成删除操作。安全提示:通过GET方式构建删除的操作非常危险,用户可以轻易掌握删除动作的URL地址,并更改id信息删除所有内容!

CakePHP路由器

CakePHP框架的默认路由能够满足绝大多数应用程序的需要。对于非常在意用户体验及搜索引擎优化的程序员来说,可能需要在程序构建完毕之后,通过CakePHP路由器更改默认的URL地址,在本教程的最后,我们简单看下CakePHP路由器。

CakePHP的默认响应请求(访问www.example.com)是使用PagesController控制器,然后输出home.ctp视图 文件,这些文件都包含在CakePHP框架的核心库中。现在我们通过路由更改默认响应到PostsController控制器的index()方法。首先 找到路由配置文件,/app/Config/routes.php。找到如下代码,并替换新的代码。

01
02
03
04
05
//注释掉:
//Router::connect(‘/‘, array(‘controller‘ => ‘pages‘, ‘action‘ => ‘display‘, ‘home‘));
 
//添加代码:
Router::connect(‘/‘, array(‘controller‘ => ‘posts‘, ‘action‘ => ‘index‘));

对于该段代码,在本教程中不做过多解释,一切正常的话,现在访问www.example.com,就可以直接转向到PostsController控制器的index()方法了。

PS:CakePHP在获取到路由信息的修改知道,会自动完成反向路由的操作。例如,添加上述路由规则之后,任何在视图文 件中,通过HtmlHelper助手link()方法的数组参数定义的链接,都会有www.example.com/posts/index自动输出为 www.example.com,你不需担心视图中还保留路由更改之前的URL链接。

CakePHP 2.x十分钟博客教程(三):数据库基础操作、表单、路由器,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。