现在我们已经构建了应用的框架,让我们讨论一下应用与 CouchDB 通信需要做些什么。
在本章中,我们将讨论以下几点:
- 研究一下与 CouchDB 交互的快捷方式,并讨论它的缺点
- 查看现有库以简化 PHP 和 CouchDB 开发
- 安装 Sag 并将其集成到骨骼中
- 让我们的注册表格创建 CouchDB 文档并与 Futon 核实
在我们开始之前
在我们做任何事情之前,让我们创建一个数据库,从现在开始,我们将使用它来创建 Verge。如前所述,让我们使用 curl创建一个数据库。
行动时间-使用 curl 为 Verge 创建数据库
我们使用第 3 章中的 curl创建了一个数据库,开始使用 CouchDB 和 Futon。让我们快速回顾一下如何使用 PUT请求在 CouchDB 中创建新数据库。
- 在终端中运行以下命令创建新数据库。确保将
username和password替换为您在第 3 章中创建的数据库管理员用户。
curl -X PUT username:password@localhost:5984/verge
- 端子将响应以下输出:
{"ok":true}
刚才发生了什么事?
我们使用终端触发 PUT请求,使用 curl通过 CouchDB 的RESTful JSON API创建数据库。我们在 CouchDB 的根 URL 末尾传递了 verge作为数据库的名称。成功创建数据库后,我们收到一条消息,表示一切正常。
头先跳水
在本节中,我们将创建一些快速而肮脏的代码来与 CouchDB 通信,然后讨论这种方法的一些问题。
为我们的注册脚本添加逻辑
在上一章中,我们在 views/signup.php中创建了一个表单,具有以下功能:
- 我们要求用户在文本框中输入 name 的值
- 我们获取表单中输入的值并将其发布到注册路线
- 我们使用 Bones 获取表单传递的值,并将其设置为一个名为
message的变量,以便在主页上显示它 - 我们呈现了主页并显示了
message变量
这对我们来说是一项艰巨的任务,但我们无法为以后的阅读或写作保留任何东西。
让我们进一步使用此表单,要求用户输入名称和电子邮件地址,然后将这些字段保存为 CouchDB 中的文档。
行动时间-向注册表单添加电子邮件字段
让我们添加一个输入字段,以便用户可以在 views/signup.php页面中输入电子邮件地址。
- 在文本编辑器中打开
signup.php(/Library/Webserver/Documents/verge/views/signup.php) - 添加突出显示的代码,为电子邮件地址添加标签和输入字段:
Signup
<form action="<?php echo $this->make_route('signup') ?>" method="post">
<label for="name">Name</label>
<input id="name" name="name" type="text"> <br />
<label for="email">Email</label>
<input id="email" name="email" type="text"> <br />
<input type="Submit" value="Submit">
</form>
刚才发生了什么事?
我们在注册表单中添加了一个额外的字段,该字段将接受电子邮件地址的输入。通过将 email字段添加到此表单,我们将能够在表单提交时访问它,并最终将其保存为 CouchDB 文档。
使用 curl 调用将数据发布到 CouchDB
在前面的章节中,我们使用了 curl到终端与 CouchDB 进行交互。你会很高兴知道你也可以通过 PHP 使用 curl。为了用 CouchDB 表示数据,我们首先需要将数据转换成 JSON 格式。
行动时间-创建标准对象以编码为 JSON
让我们以 JSON 的形式表示一个简单的对象,以便 CouchDB 能够解释它。
在文本编辑器中打开 index.php,在 /signup POST路径中添加以下代码:
post('/signup', function($app) {
$user = new stdClass;
$user->type = 'user';
$user->name = $app->form('name');
$user->email = $app->form('email');
echo json_encode($user);
$app->set('message', 'Thanks for Signing Up ' . $app->form('name') . '!');
$app->render('home');
});
刚才发生了什么事?
我们添加了代码来创建一个对象来存储用户的细节。我们使用了一个 stdClass的实例,称之为 $user. stdClass是 PHP 的泛型空类,它对匿名对象、动态属性和启动运行非常有用。因为文档需要设置一个类型来对文档进行分类,所以我们将此文档的类型设置为 user。然后,我们将表单中提交的值保存为 $user类的属性。最后,我们使用一个名为 json_encode的 PHP 函数获取对象并创建其 JSON 表示。
让我们来测试一下。
- 打开浏览器至
http://localhost/verge/signup。 - 在姓名文本框中输入
John Doe,在电子邮件文本框中输入<[[email protected]](https://raw.githubusercontent.com/apachecn/apachecn-php-zh/master/docs/couchdb-php-web-dev-begin-guide/mailto:[email protected])>。 - 点击提交。
- Your browser will display the following:

完美的我们的表格提交正确,我们能够在网站顶部用 JSON 表示 stdClass $user。
将其提交给 Git
让我们将我们的代码提交给 Git,这样我们就可以回头看看这段代码了。
- 打开终端。
- 键入以下命令将目录更改为我们的工作目录:
cd /Library/Webserver/Documents/verge/
- 向 Git 描述自上次提交以来我们所做的工作:
git commit am 'Added functionality to collect name and email through stdClass and display it onscreen.'
现在我们已经用 JSON 表示了我们的数据,让我们使用一个 curl语句来使用 PHP 创建一个 CouchDB 文档。
行动时间到了-使用 PHP 和 curl 创建 CouchDB 文档
从本书开始,我们就一直在通过命令行使用 curl,但这次,我们将使用 PHP 触发一个 curl语句。
- 让我们先初始化一个
curl会话,执行它,然后关闭它。在文本编辑器中打开index.php并将以下代码添加到/signup POST路由中:
post('/signup', function($app) {
$user = new stdClass;
$user->type = 'user';
$user->name = $app->form('name');
$user->email = $app->form('email');
echo json_encode($user);
$curl = curl_init();
// curl options
curl_exec($curl);
curl_close($curl);
$app->set('message', 'Thanks for Signing Up ' . $app- >form('name') . '!');
$app->render('home');
});
- 现在,让我们告诉
curl实际执行什么。我们用一个options数组来实现这一点。在curl_init()和curl_exec语句之间添加以下代码:
post('/signup', function($app) {
$user = new stdClass;
$user->name = $app->form('name');
$user->email = $app->form('email');
echo json_encode($user);
$curl = curl_init();
// curl options
$options = array(
CURLOPT_URL => 'localhost:5984/verge',
CURLOPT_POSTFIELDS => json_encode($user),
CURLOPT_HTTPHEADER => array ("Content-Type: application/json"),
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "utf-8",
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_AUTOREFERER => true
);
curl_setopt_array($curl, $options);
curl_exec($curl);
curl_close($curl);
$app->set('message', 'Thanks for Signing Up ' . $app-> form('name') . '!');
$app->render('home');
});
刚才发生了什么事?
我们使用 PHP 初始化了一个 curl会话,首先使用 curl_init()资源设置一个变量 $curl。然后,我们创建了一个包含各种键和值的数组。我们选择所有这些选项的原因现在对我们来说并不重要,但我想强调前三个对象:
- 我们正在将
CURLOPT_URL选项设置为要将文档保存到的数据库的 URL。请记住,此语句将使用 CouchDB 的 RESTful JSON API 在verge数据库中创建一个文档。 - 然后我们将
CURLOPT_POSTFIELDS设置为$user的 JSON 编码值。这将获取我们的 JSON 字符串,并将其与 URL 一起作为数据包含。 - 最后,我们将
CURLOPT_HTTPHEADER设置为array ("Content-Type: application/json"),以便确保curl知道我们正在传递 JSON 请求。
有了选项数组集,我们需要告诉 curl实例使用它:
curl_setopt_array($curl, $options);
然后,我们使用以下两行代码执行并关闭 curl:
curl_exec($curl);
curl_close($curl);
在应用中使用此代码,我们应该能够提交表单并将其发布到 CouchDB。让我们测试一下。
- 打开浏览器至
http://localhost/verge/signup。 - 在姓名文本框中输入
John Doe,在电子邮件文本框中输入<[[email protected]](https://raw.githubusercontent.com/apachecn/apachecn-php-zh/master/docs/couchdb-php-web-dev-begin-guide/mailto:[email protected])>。 - 点击提交。
- Your browser will display the following:

和以前一样,它运行良好,没有任何错误。但这一次,应该创建一个 CouchDB 文档。让我们检查一下文档是否使用 Futon 正确创建。
- Open your browser to
http://localhost:5984/_utils/database.html?verge. This direct link will show you the verge database. You'll see that there's a new document in here! Keep in mind that yourIDandrevwill be different from mine:

- 单击文档,以便查看详细信息。
- The data in your document should match up to the information that we passed in using our
curlsession. Notice thattype, email, andnamewere all set properly, and that CouchDB set_idand_revfor us.

将其提交给 Git
让我们将代码提交给 Git,以便将来可以再次引用此代码。
- 打开终端。
- 键入以下命令将目录更改为我们的工作目录:
cd /Library/Webserver/Documents/verge/
- 向 Git 描述自上次提交以来我们所做的工作:
git commit am 'CouchDB Documents can now be created through the signup form using curl.'
我们只是研究了使用 PHP 创建 CouchDB 文档的最简单方法之一。然而,我们需要评估我们刚刚编写的代码是否是可持续的,是否是我们开发应用的明智方法。
这项技术足够好吗?
这个问题很难回答。从技术上讲,我们可以用这种方式构建我们的应用,但我们需要添加更多的代码,并在本书的其余部分花时间重构对 curl的调用,直到它完美工作为止。然后,我们需要花费大量时间将调用重构到一个简单的库中,以便更容易修复。简而言之,这种技术不起作用,因为我们希望专注于构建应用,而不是整理 PHP 和 CouchDB 之间的所有通信问题。幸运的是,我们可以使用各种 CouchDB 库来简化开发过程。
可用的 CouchDB 库
在使用 PHP 和 CouchDB 进行开发时,有各种各样的库可以使我们的生活更加轻松。所有的库都是开源项目,这太棒了!但是,这些库中的一些还没有被积极地用于支持 CouchDB 的新版本。因此,我们需要有选择性地选择与我们合作的图书馆。
这里可以看到一些 PHP 和 CouchDB 库的列表:http://wiki.apache.org/couchdb/Getting_started_with_PHP ,还有很多其他托管在 GitHub 上的东西需要进一步挖掘。
每个库都有各自的优点,但由于简单性是 Bones 的关键概念,因此我们也应该在 PHP 库中努力实现简单性。话虽如此,我们的最佳解决方案称为Sag。
弧垂
Sag 是 Sam Bisbee 创建的 CouchDB 的伟大 PHP 库。Sag 的指导原则是简单,创建一个功能强大的接口,开销很小,可以轻松地与任何应用结构集成。它不会强制您的应用使用框架、文档专用类或 ORM,但如果您愿意,您仍然可以这样做。Sag 接受基本的 PHP 数据结构(对象、字符串等),并返回原始 JSON 或对象中的响应和 HTTP 信息。
我将带您了解 Sag 的安装和基本功能,但您也可以访问 Sag 的网站:http://www.saggingcouch.com/ 用于示例和文档。
下载和设置 Sag
Sag 非常低调,适合我们当前的应用结构。我们所需要做的就是使用 Git 从其 GitHub 存储库中获取 Sag,并将其放在我们的 lib目录中。
行动时间-使用 Git 安装 Sag
Git 使建立第三方库变得非常容易,并允许我们在新版本可用时进行更新。
- 打开终端。
- 键入以下命令以确保您在工作目录中:
cd /Library/Webserver/Documents/verge/
- 使用 Git:
git submodule add git://github.com/sbisbee/sag.git lib/sag
git submodule init
将 Sag 添加到我们的存储库中
刚才发生了什么事?
我们使用 Git 使用 git submodule add将 Sag 添加到我们的项目中,然后通过键入 git submodule init初始化子模块。Git 的子模块允许我们在存储库中拥有一个成熟的 Git 存储库。每当 Sag 发布新版本时,您都可以运行 git submodule update,您将收到最新、最棒的代码。
增加骨骼下垂
为了使用 Sag,我们将在 Bones中添加几行,以确保我们的库可以看到并使用它。
行动时间-增加骨骼下垂
启用和设置 Sag 以使用 Bones非常简单。让我们一起走过它!
- 在我们的工作目录中打开
lib/bones.php,并在我们班的顶部添加以下行:
<?php
define('ROOT', __DIR__ . '/..');
require_once ROOT . '/lib/sag/src/Sag.php';
- 我们需要确保 Sag 已准备就绪,并在每次请求时可用。让我们在
Bones中添加一个名为$couch的新变量,并在__construct函数中设置它:
public $route_segments = array();
public $route_variables = array();
public $couch;
public function __construct() {
$this->route = $this->get_route();
$this->route_segments = explode('/', trim($this->route, '/'));
$this->method = $this->get_method();
$this->couch = new Sag('127.0.0.1', '5984');
$this->couch->setDatabase('verge');
}
刚才发生了什么事?
我们通过使用 require_once加载 Sag 资源,确保 Bones能够访问和使用 Sag。然后,我们确保每次构建 Bones时,我们都会定义数据库服务器和端口,并设置要使用的数据库。
注
请注意,我们不需要任何凭据来与 Verge数据库交互,因为我们尚未对此数据库设置任何权限。
使用 Sag 简化我们的代码
在我们的应用中包含 Sag 后,我们可以简化数据库调用,将处理和异常处理交给 Sag,并专注于构建我们的产品。
行动时间-创建带有 Sag 的文档
现在我们已经有了 Sag,可以在应用中的任何地方使用了,让我们重构保存在 /signup post路径中的用户类。
打开 index.php,删除我们在前面章节中添加的所有额外代码,这样我们的 /signup post路径看起来与下面的代码片段类似:
post('/signup', function($app) {
$user = new stdClass;
$user->name = $app->form('name');
$user->email = $app->form('email');
$app->couch->post($user);
$app->set('message', 'Thanks for Signing Up ' . $app->form('name') . '!');
$app->render('home');
});
刚才发生了什么事?
我们使用 Sag 创建了一个到 CouchDB 数据库的帖子,使用的代码更少!Sag 的 post 方法允许您使用它传递数据,因此触发起来非常容易。
让我们再次快速完成注册过程:
- 打开浏览器至
http://localhost/verge/signup。 - 在名称文本框中输入新名称,在电子邮件文本框中输入新电子邮件。
- 点击提交。
CouchDB 中创建了一个新文档,所以让我们检查 Futon 以确保它在那里:
- 打开浏览器至
http://localhost:5984/_utils/database.html?verge,查看 verge 数据库。 - 单击列表中的第二个文档。
- 查看这个新文档的详细信息,您将看到它与我们制作的第一个文档具有相同的结构。
完美的结果与我们的快速脏卷曲脚本完全一样,但我们的代码要简单得多,Sag 在幕后为我们处理了很多事情。
注
我们目前没有捕获或处理任何错误。我们将在以后的章节中更多地讨论如何处理这些问题。谢天谢地,CouchDB 以友好的方式处理错误,Sag 确保了追踪问题的容易性。
增加更多结构
我们可以如此轻松地创建文档,这很好,但同样重要的是,我们有一个强大的类结构,使我们能够保持组织。
行动时间-包括类目录
为了让我们使用我们的类,我们需要在 Bones中添加一些代码,这样我们就可以在使用类名时自动加载它们。这将实现这一点,因此我们不必在添加新类时不断包含更多的文件。
将以下代码添加到 lib/bones.php:
<?php
define('ROOT', __DIR__ . '/..');
require_once ROOT . '/lib/sag/src/Sag.php';
function __autoload($classname) {
include_once(ROOT . "/classes/" . strtolower($classname) . ".php");
}
刚才发生了什么事?
我们在 Bones库中添加了一个 __autoload函数,如果 PHP 找不到类名,它将给 PHP 最后一次加载类名的尝试。 __autoload函数通过 $classname传递,我们使用 $classname查找命名类的文件。我们正在使用 strtolower函数将请求的 $classname小写,以便找到命名文件。然后,我们用 ROOT常量和 classes文件夹添加了工作目录的根。
与班级一起工作
现在我们已经能够加载类了,让我们创建一些!我们将首先创建一个基类,所有其他类都将从该基类继承属性。
行动时间-创建基础对象
在本节中,我们将创建一个名为 base.php的基类,所有类都将继承该基类。
- 首先,我们创建一个名为
base.php的新文件,并将其放置在工作目录(/Library/Webserver/Documents/verge/classes/base.php中)的 classes 文件夹中 - 在
base.php中创建具有__construct函数的抽象类。在对象的__construct上,我们将$type作为一个选项,并将其设置为一个受保护的变量,也称为$type。
<?php
abstract class Base
{
protected $type;
public function __construct($type)
{
$this->type = $type;
}
}
- 为了便于以后在我们的类中获取和设置变量,让我们在
__construct函数之后添加__get()和__set()函数。
<?php
abstract class Base
{
protected $type;
public function __construct($type)
{
$this->type = $type;
}
public function __get($property) {
return $this->$property;
}
public function __set($property, $value) {
$this->$property = $value;
}
}
- 每次我们将对象保存到 couchdb 时,我们都希望能够用 JSON 字符串表示它。因此,让我们创建一个名为
to_json()的助手函数,它将把我们的对象转换成 JSON 格式。
<?php
abstract class Base
{
protected $type;
public function __construct($type)
{
$this->type = $type;
}
public function __get($property) {
return $this->$property;
}
public function __set($property, $value) {
$this->$property = $value;
}
public function to_json() {
return json_encode(get_object_vars($this));
}
}
刚才发生了什么事?
我们创建了一个名为 base.php的基类,它将作为我们构建的所有其他类的基础。在类内部,我们定义了一个名为 $type的受保护变量,它将存储文档的分类,如 user或 post。接下来,我们添加了一个 __construct函数,该函数将在每次创建对象时调用。此函数接受选项 $type,我们将在 Base上扩展的每个类中设置该选项。然后我们创建了 __get和 __set函数。 __get和 __set被称为魔法方法,允许我们使用 get和 set保护变量,而无需任何额外代码。最后,我们添加了一个名为 to_json的函数,它使用 get_object_vars和 json_encode以 JSON 字符串表示我们的对象。在我们的基层做这样的小事会让我们的生活更轻松。
行动时间-创建用户对象
现在我们已经创建了 Base类,让我们创建一个 User类,该类将包含与用户相关的所有内容的属性和函数。
- 创建一个名为
user.php的新文件,并将其与base.php一起放入classes文件夹中。 - 让我们创建一个扩展
Base类的类。
<?php
class User extends Base
{
}
- 让我们将我们目前所需要的两个属性添加到我们的
User类中:name和email。
<?php
class User extends Base
{
protected $name;
protected $email;
}
- 让我们添加一个
__construct函数,告诉我们的Base类我们的文档类型在创建时是user。
<?php
class User extends Base
{
protected $name;
protected $email;
public function __construct()
{
parent::__construct('user');
}
}
刚才发生了什么事?
我们创建了一个名为 user.php的简单类,它扩展了 Base。扩展意味着它将继承可用的属性和函数,以便我们可以利用它们。然后,我们纳入了两个受保护的财产,分别称为 $name和 $email。最后,我们创建了一个 __construct函数。此实例中的构造告诉父类(即我们的 Base类)文档的类型为 user。
行动时间-插入用户对象
在我们的系统中有了新的 User对象,我们可以很容易地将其插入到应用代码中,我们应该可以启动并运行它。
- 打开
index.php文件,将stdClass改为User()。当我们进行此操作时,我们还可以删除$user->type = 'user',因为它现在在我们的类中处理:
post('/signup', function($app) {
$user = new User();
$user->name = $app->form('name');
$user->email = $app->form('email');
$app->couch->post($user);
}
- 调整 Sag
post语句,以便我们可以通过 JSON 格式的类:
post('/signup', function($app) {
$user = new User();
$user->name = $app->form('name');
$user->email = $app->form('email');
$app->couch->post($user->to_json);
}
刚才发生了什么事?
我们将 stdClass的实例替换为 User()。这将使我们能够完全控制获取和设置变量。然后我们删除了 $user->type = 'user',因为 User和 Base对象中的 __construct函数已经处理了这个问题。最后,我们添加了前面创建的 to_json()函数,以便可以将对象作为 JSON 编码的字符串发送。
注
从技术上讲,Sag 可以使用 JSON 单独处理对象,但重要的是我们能够从对象中检索 JSON 字符串,以便您可以以任何方式与 CouchDB 交互。有可能在将来的某一天,您可能需要返回并使用 curl或其他库重写所有内容。因此,了解如何用 JSON 表示数据非常重要。
测试一下
让我们再次快速完成注册过程,以确保一切正常:
- 打开浏览器至
http://localhost/verge/signup。 - 在名称文本框中输入新名称,在电子邮件文本框中输入新电子邮件。
- 点击提交。
应该在 CouchDB 中创建一个新文档。让我们检查一下蒲团,确保它在那里:
- 打开浏览器至
http://localhost:5984/_utils/database.html?verge查看 verge 数据库。 - 单击列表中的第三个文档
- 查看这个新文档的详细信息,您将看到它与我们制作的前两个文档具有相同的结构。
完美的一切都像以前一样工作,但我们现在使用的是一个更优雅的解决方案,我们将能够在未来的章节中构建它。
将其提交给 Git
让我们将代码提交给 Git,这样我们就可以跟踪到目前为止的进度:
- 打开终端。
- 键入以下命令将目录更改为我们的工作目录:
cd /Library/Webserver/Documents/verge/
- 我们在
classes文件夹中添加了一些新文件。所以,让我们确保将这些文件添加到 Git。
git add classes/*
- 向 Git 描述自上次提交以来我们所做的工作:
git commit am 'Added class structure for Users and tested its functionality'
通过使用 classes/* syntax,我们告诉 Git 添加 classes 文件夹中的每个文件。当您添加了多个文件并且不想单独添加每个文件时,这非常方便。
收工
我们已经完成了本章的代码。偶尔将代码推送到 GitHub 总是一个好的做法。事实上,当您与多个开发人员合作时,这是至关重要的。在这本书中,我不再提醒你这样做了。因此,请确保经常这样做:
git push origin master
如果只在代码之间添加几个单词,那么这行代码读起来就像一个句子。这句话告诉 Git 将 push发送到 origin(我们将其定义为 GitHub),我们希望发送 master分支。
总结
我希望你喜欢这一章。当所有这些技术一起工作并允许我们轻松地将内容保存到 CouchDB 时,这是很有趣的。
让我们回顾一下我们在本章中讨论的内容:
- 我们研究了使用 PHP 与 CouchDB 对话的几种不同方式
- 我们把它绑在骨头上
- 我们构建了一个面向对象的类结构,这将为我们节省很多麻烦
- 我们进行了测试,以确保在提交注册表单时创建了 CouchDB 文档
在下一章中,我们将积极研究 CouchDB 已经为我们的用户插入的一些强大功能,以及如何使用 CouchDB 构建大多数应用所具有的标准注册和登录过程。伸出你的打字手指,给自己弄一杯美味的大杯咖啡,因为我们就要有真正的乐趣了。