模型是CakePHP应用程序的面包和黄油。 通过创建一个将与我们的数据库交互的CakePHP模型,我们将有需要的基础来执行我们的查看,添加,编辑和删除操作。
CakePHP的模型类文件分为表和实体对象。表对象提供的实体集合存储在一个特定的表,然后在src/Model/Table。文件我们会创建将保存到src/Model/Table/ArticlesTable.php。完成的文件应该如下:
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
}
}
在CakePHP命名规则是非常重要的。通过命名我们的Table对象
ArticlesTable
,CakePHP可以自动推断出这个Table对象将在ArticlesController
中使用,并且将绑定到一个名为articles
的数据库表。
▲ 注意: 如果CakePHP在src / Model / Table中找不到相应的文件,它将为您动态创建一个模型对象。 这也意味着如果你不小心命名你的文件错误(即articlestable.php或ArticleTable.php),CakePHP将不会识别你的任何设置,并将使用生成的模型。
有关模型的更多信息,例如回调和验证,请查看本手册的数据库访问和ORM章节。
▲ 注意: 如果您完成CakePHP系列(二)----博客(Blog)案例(一)并在我们的博客数据库中创建了articles表,您可以利用CakePHP的用Bake生成功能来创建ArticlesTable模型:
有Bake生成代码功能的更多信息,请访问Bake生成代码。
创建文章控制器
接下来,我们将为我们的文章创建一个控制器。 控制器是所有与文章的交互发生的地方。 简而言之,它是你使用模型中包含的业务逻辑并获得与文章相关的工作的地方。 我们将把这个新的控制器放在一个名为ArticlesController.php的src / Controller目录下的文件中。 下面是基本控制器应该是什么样子:
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
}
现在,让我们给我们的控制器添加一个动作。 操作通常表示应用程序中的单个函数或接口。 例如,当用户请求www.example.com/articles/index(也与www.example.com/articles/相同)时,他们可能会看到文章列表。 该操作的代码如下所示:
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
public function index()
{
$articles = $this->Articles->find('all');
$this->set(compact('articles'));
}
}
通过在ArticlesController中定义函数index() ,用户现在可以通过请求www.example.com/articles/index来访问逻辑。 同样,如果我们要定义一个名为foobar()的函数,用户将能够访问www.example.com/articles/foobar。
您可能会试图以某种方式命名您的控制器和操作以获取某个URL。 抵制这种诱惑。 遵循CakePHP约定 (大写,复数名称等),并创建可读,可理解的动作名称。 您可以使用稍后介绍的Routing将网址映射到您的代码。
操作中的单个指令使用set()
将数据从控制器传递到视图(我们将在下面创建)。 该行将视图变量“articles”设置为等于ArticlesTable
对象的find('all')
方法的返回值。
▲ 注意: 如果您完成CakePHP系列(二)----博客(Blog)案例(一)并在您的博客数据库中创建了articles表,您可以利用CakePHP的Bake生成代码功能来创建ArticlesController类:
bin/cake bake controller Articles
有Bake生成代码功能的更多信息,请访问 Bake生成代码 。
要了解有关CakePHP控制器的更多信息,请查看控制器章节。
创建文章视图
现在我们的数据来自我们的模型,我们的应用程序逻辑由我们的控制器定义,让我们为上面创建的索引操作创建一个视图。
CakePHP视图只是表示风格的片段,适合应用程序的布局。 对于大多数应用程序,它们是HTML与PHP混合的,但它们可能最终作为XML,CSV或甚至二进制数据。
布局是环绕视图的表示代码。 可以定义多个布局,您可以在它们之间切换,但现在,让我们使用默认值。
记住在最后一节中我们如何使用set()
方法将“articles”变量分配给视图? 这将递归查询对象集合到要使用foreach
迭代调用的视图。
CakePHP的模板文件存储在src / Template文件夹中,它们对应的控制器之后(在这种情况下我们需要创建一个名为“Articles”的文件夹)。 要在一个漂亮的表中格式化这篇文章数据,我们的视图代码可能看起来像这样:
<!-- File: src/Template/Articles/index.ctp -->
<h1>Blog articles</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<!-- Here is where we iterate through our $articles query object, printing out article info -->
<?php foreach ($articles as $article): ?>
<tr>
<td><?= $article->id ?></td>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->id]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
希望这应该看起来有点简单。
你可能已经注意到使用一个名为$this->Html
的对象。 这是CakePHP Cake\View\Helper\HtmlHelper
类的一个实例。 CakePHP带有一组视图助手,使得事情像链接,形式输出一个快照。 你可以更多地了解如何在Helpers中使用它们,但是需要注意的是, link()
方法将生成一个带有给定标题(第一个参数)和URL(第二个参数)的HTML链接。
在CakePHP中指定URL时,建议使用数组格式。 这将在“路由”一节中更详细地解释。 使用URL的数组格式允许您利用CakePHP的反向路由功能。 您还可以以/controller/action/param1/param2
的形式指定相对于应用程序基本的URL,或使用命名的路由 。
此时,您应该可以将浏览器指向http://www.example.com/articles/index 。 您应该看到您的视图,正确格式化的文章的标题和表列表。
如果你碰巧点击了我们在这个视图中创建的链接之一(将文章的标题链接到URL /articles/view/some\_id
),那么你可能已经被CakePHP通知,该操作尚未定义。 如果你没有这么知情,或者有什么问题,或者你实际上已经定义了它,在这种情况下你是非常鬼祟。 否则,我们将在ArticlesController
创建它:
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
public function index()
{
$this->set('articles', $this->Articles->find('all'));
}
public function view($id = null)
{
$article = $this->Articles->get($id);
$this->set(compact('article'));
}
}
set()
调用应该看起来很熟悉。 注意,我们使用get()
而不是find('all')
,因为我们只想要一篇文章的信息。
请注意,我们的查看操作需要一个参数:我们希望查看的文章的ID。 此参数通过请求的URL传递到操作。 如果用户请求/articles/view/3
,则值“3”作为$id
传递。
我们还做一些错误检查,以确保用户实际访问记录。 通过在Articles表中使用get()
函数,我们确保用户已经访问了一个存在的记录。 如果请求的文章不存在于数据库中,或者id为false, get()
函数将抛出一个NotFoundException
。
现在让我们为新的'view'操作创建视图,并将其放在src / Template / Articles / view.ctp中
<!-- File: src/Template/Articles/view.ctp -->
<h1><?= h($article->title) ?></h1>
<p><?= h($article->body) ?></p>
<p><small>Created: <?= $article->created->format(DATE_RFC850) ?></small></p>
通过尝试
/articles/index
的链接或通过访问/articles/view/{id}
手动请求文章,并用文章“id”替换{id}
来验证此操作是否正常。
添加文章
从数据库中读取并显示文章是一个伟大的开始,但让我们允许添加新文章。
首先,从ArticlesController
中创建一个add()
动作:
// src/Controller/ArticlesController.php
namespace App\Controller;
use App\Controller\AppController;
class ArticlesController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Flash'); // Include the FlashComponent
}
public function index()
{
$this->set('articles', $this->Articles->find('all'));
}
public function view($id)
{
$article = $this->Articles->get($id);
$this->set(compact('article'));
}
public function add()
{
$article = $this->Articles->newEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your article.'));
}
$this->set('article', $article);
}
}
▲ 注意: 您需要将Flash组件包含在将要使用的任何控制器中。 如果有必要,将其包含在AppController 。
这里是add()
动作的作用:如果请求的HTTP方法是POST,尝试使用Articles模型保存数据。 如果由于某种原因它不保存,只是渲染视图。 这使我们有机会显示用户验证错误或其他警告。
每个CakePHP请求都包含一个可以使用$this->request
的Request
对象。 请求对象包含有关刚刚收到的请求的有用信息,可用于控制应用程序的流程。 在这种情况下,我们使用Cake\Network\Request::is()
方法来检查请求是否是HTTP POST请求。
当用户使用表单向您的应用程序POST数据时,该信息位于$this->request->getData()
。 你可以使用pr()
或debug()
函数打印出来,如果你想看看它的外观。
我们使用FlashComponent的success()
和error()
方法来将消息设置为会话变量。 这些方法是使用PHP的magic method特性提供的 。 重定向后,页面上将显示Flash消息。 在布局中,我们有<?= $this->Flash->render() ?>
,它显示消息并清除相应的会话变量。 控制器的Cake\Controller\Controller::redirect
函数重定向到另一个URL。 param['action' => 'index']
转换为URL / articles,即ArticlesController
的索引操作。 您可以参考API上的Cake\Routing\Router::url()
函数来查看可以为其指定各种CakePHP函数的URL的格式。
调用save()
方法将检查验证错误并中止保存(如果发生)。 我们将在下面的部分讨论如何处理这些错误。
数据验证
CakePHP对于从形式输入验证中获得单调性有很大的帮助。 每个人都讨厌编码无尽的形式和他们的验证程序。 CakePHP使它更容易和更快。
要利用验证功能,您需要在视图中使用CakePHP的Form助手。 Cake\View\Helper\FormHelper
默认情况下可用于$this->Form
中的所有视图。
<!-- File: src/Template/Articles/add.ctp -->
<h1>Add Article</h1>
<?php
echo $this->Form->create($article);
echo $this->Form->input('title');
echo $this->Form->input('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();
?>
我们使用FormHelper生成HTML表单的开始标签。 这里是$this->Form->create()
Form- $this->Form->create()
生成的HTML:
<form method= action=>
如果在没有提供参数的情况下调用create()
,则它假定您正在构建一个表单,通过POST将其提交到当前控制器的add()
动作(或在表单数据中包含id
时的edit()
动作)。
$this->Form->input()
方法用于创建同名的表单元素。 第一个参数告诉CakePHP它们对应的字段,第二个参数允许你指定一个宽的数组 - 在这种情况下,textarea的行数。 这里有一点自省和自动: input()
将根据指定的模型字段输出不同的表单元素。
$this->Form->end()
调用结束表单。 如果启用CSRF /表单防篡改,则输出隐藏输入。
现在让我们回去更新我们的src / Template / Articles / index.ctp视图,包括一个新的“添加文章”链接。 在<table>
之前,添加以下行:
<?= $this->Html->link('Add Article', ['action' => 'add']) ?>
您可能想知道:我如何告诉CakePHP关于我的验证要求? 验证规则在模型中定义。 让我们回顾一下我们的文章模型,并做一些调整:
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
}
public function validationDefault(Validator $validator)
{
$validator
->notEmpty('title')
->requirePresence('title')
->notEmpty('body')
->requirePresence('body');
return $validator;
}
}
validationDefault()
方法告诉CakePHP如何在调用save()
方法时验证数据。 在这里,我们已经指定body和title字段不能为空,并且对于创建和更新操作都是必需的。 CakePHP的验证引擎是强大的,有一些预建的规则(信用卡号码,电子邮件地址等)和灵活性,以添加您自己的验证规则。 有关该设置的更多信息,请查看验证文档。
现在您的验证规则已就位,请使用应用程序尝试添加具有空标题或正文的文章,以查看其工作原理。 由于我们已经使用Cake\View\Helper\FormHelper::input()
的Cake\View\Helper\FormHelper::input()
方法创建表单元素,因此将自动显示验证错误消息。
编辑文章
后编辑:这里我们去。 你现在是一个CakePHP专家,所以你应该选择一个模式。 做动作,然后视图。 这里是ArticlesController
的edit()
动作将是什么样子:
// src/Controller/ArticlesController.php
public function edit($id = null)
{
$article = $this->Articles->get($id);
if ($this->request->is(['post', 'put'])) {
$this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been updated.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to update your article.'));
}
$this->set('article', $article);
}
此操作首先确保用户已尝试访问现有记录。 如果他们没有传入一个$id
参数,或者文章不存在,我们抛出一个NotFoundException
为CakePHP ErrorHandler照顾。
接下来,操作将检查请求是POST还是PUT请求。 如果是,那么我们使用POST数据通过使用patchEntity()
方法来更新我们的article实体。 最后,我们使用表对象来保存实体或回退并显示用户验证错误。
编辑视图可能如下所示:
<!-- File: src/Template/Articles/edit.ctp -->
<h1>Edit Article</h1>
<?php
echo $this->Form->create($article);
echo $this->Form->input('title');
echo $this->Form->input('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();
?>
此视图输出编辑表单(带有填充的值),以及任何必要的验证错误消息。
CakePHP将确定一个save()
是否基于实体的状态生成一个插入或更新语句。
您现在可以通过链接更新索引视图,以编辑特定文章:
<!-- File: src/Template/Articles/index.ctp (edit links added) -->
<h1>Blog articles</h1>
<p><?= $this->Html->link(, ['action' => 'add']) ?></p>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
<th>Action</th>
</tr>
<!-- Here's where we iterate through our $articles query object, printing out article info -->
<?php foreach ($articles as $article): ?>
<tr>
<td><?= $article->id ?></td>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->id]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('Edit', ['action' => 'edit', $article->id]) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
删除文章
接下来,让我们让用户删除文章。 从ArticlesController
中的delete()
动作ArticlesController
:
// src/Controller/ArticlesController.php
public function delete($id)
{
$this->request->allowMethod(['post', 'delete']);
$article = $this->Articles->get($id);
if ($this->Articles->delete($article)) {
$this->Flash->success(__('The article with id: {0} has been deleted.', h($id)));
return $this->redirect(['action' => 'index']);
}
}
此逻辑删除$id
指定的文章,并使用$this->Flash->success()
在将用户重定向到/articles
后向用户显示确认消息。 如果用户尝试使用GET请求执行删除, allowMethod()
将抛出一个异常。 未捕获的异常由CakePHP的异常处理程序捕获,并显示一个漂亮的错误页面。 有许多内置的异常可用于指示应用程序可能需要生成的各种HTTP错误。
因为我们只是执行一些逻辑和重定向,这个动作没有视图。 您可能希望使用允许用户删除文章的链接更新索引视图,但是:
<!-- File: src/Template/Articles/index.ctp (delete links added) -->
<h1>Blog articles</h1>
<p><?= $this->Html->link('Add Article', ['action' => 'add']) ?></p>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
<th>Actions</th>
</tr>
<!-- Here's where we loop through our $articles query object, printing out article info -->
<?php foreach ($articles as $article): ?>
<tr>
<td><?= $article->id ?></td>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->id]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Form->postLink(
'Delete',
['action' => 'delete', $article->id],
['confirm' => 'Are you sure?'])
?>
<?= $this->Html->link('Edit', ['action' => 'edit', $article->id]) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
使用View\Helper\FormHelper::postLink()将创建一个链接,使用JavaScript来执行POST请求删除我们的文章。
▲ 注意: 允许使用GET请求删除内容很危险,因为网络抓取工具可能会意外删除您的所有内容。此视图代码还使用FormHelper在尝试删除文章之前提示用户使用JavaScript确认对话框。
路由
对于一些,CakePHP的默认路由工作得很好。 对用户友好和一般搜索引擎兼容性敏感的开发人员将会喜欢CakePHP的URL映射到特定操作的方式。 因此,我们将在本教程中快速更改路线。
有关高级路由技术的详细信息,请参阅连接路由 。
默认情况下,CakePHP使用其PagesController
响应对您网站根目录的请求(例如http://www.example.com ),渲染一个名为“home”的视图。 相反,我们将通过创建一个路由规则来替换为ArticlesController。
CakePHP的路由在config / routes.php中找到。 您需要注释掉或删除定义默认根路由的行。 它看起来像这样:
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
ArticlesController
的index()
动作。
▲ 注意: CakePHP也使用“反向路由”。 如果在定义了上述路由的情况下,将['controller' => 'Articles', 'action' => 'index']传递给需要数组的函数,则使用的结果URL将为'/'。 因此,最好始终为网址使用数组,因为这意味着您的路由会定义网址所在的位置,并确保链接指向相同的位置。
结论
以这种方式创建应用程序将赢得你的和平,荣誉,爱和金钱,甚至超出了你最疯狂的幻想。 简单,不是吗? 请记住,本教程是非常基本的。 CakePHP有更多的功能,并且灵活的方式,我们不希望在这里为简单起见。 使用本手册的其余部分作为构建更多功能丰富的应用程序的指南。
现在您已经创建了一个基本的CakePHP应用程序,您可以继续CakePHP系列(二)----博客(Blog)案例(三) ,或开始自己的项目。 您还可以阅读使用CakePHP或API <https://api.cakephp.org/3.0>了解有关CakePHP的更多信息。
如果您需要帮助,有很多方法可以获得您需要的帮助 - 请参阅“ 在哪里获取帮助”页面。 欢迎来到CakePHP!
建议的后续阅读
这些是人们学习CakePHP通常想要学习的常见任务:
- 布局 :自定义您的网站布局
- 元素 :包含和重复使用视图片段
- 使用Bake生成代码:生成基本的CRUD代码
- 博客教程 - 认证和授权 :用户认证和授权教程