现在我们已经构建了应用的框架,让我们讨论一下应用与 CouchDB 通信需要做些什么。

在本章中,我们将讨论以下几点:

  • 研究一下与 CouchDB 交互的快捷方式,并讨论它的缺点
  • 查看现有库以简化 PHP 和 CouchDB 开发
  • 安装 Sag 并将其集成到骨骼中
  • 让我们的注册表格创建 CouchDB 文档并与 Futon 核实

在我们开始之前

在我们做任何事情之前,让我们创建一个数据库,从现在开始,我们将使用它来创建 Verge。如前所述,让我们使用 curl创建一个数据库。

行动时间-使用 curl 为 Verge 创建数据库

我们使用第 3 章中的 curl创建了一个数据库,开始使用 CouchDB 和 Futon。让我们快速回顾一下如何使用 PUT请求在 CouchDB 中创建新数据库。

  1. 在终端中运行以下命令创建新数据库。确保将 username和 password替换为您在第 3 章中创建的数据库管理员用户。
    curl -X PUT username:password@localhost:5984/verge 

    
  1. 端子将响应以下输出:
    {"ok":true} 

    

刚才发生了什么事?

我们使用终端触发 PUT请求,使用 curl通过 CouchDB 的RESTful JSON API创建数据库。我们在 CouchDB 的根 URL 末尾传递了 verge作为数据库的名称。成功创建数据库后,我们收到一条消息,表示一切正常。

头先跳水

在本节中,我们将创建一些快速而肮脏的代码来与 CouchDB 通信,然后讨论这种方法的一些问题。

为我们的注册脚本添加逻辑

在上一章中,我们在 views/signup.php中创建了一个表单,具有以下功能:

  • 我们要求用户在文本框中输入 name 的值
  • 我们获取表单中输入的值并将其发布到注册路线
  • 我们使用 Bones 获取表单传递的值,并将其设置为一个名为 message的变量,以便在主页上显示它
  • 我们呈现了主页并显示了 message变量

这对我们来说是一项艰巨的任务,但我们无法为以后的阅读或写作保留任何东西。

让我们进一步使用此表单,要求用户输入名称和电子邮件地址,然后将这些字段保存为 CouchDB 中的文档。

行动时间-向注册表单添加电子邮件字段

让我们添加一个输入字段,以便用户可以在 views/signup.php页面中输入电子邮件地址。

  1. 在文本编辑器中打开 signup.php(/Library/Webserver/Documents/verge/views/signup.php)
  2. 添加突出显示的代码,为电子邮件地址添加标签和输入字段:
    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 表示。

让我们来测试一下。

  1. 打开浏览器至 http://localhost/verge/signup。
  2. 在姓名文本框中输入 John Doe,在电子邮件文本框中输入<[[email protected]](https://raw.githubusercontent.com/apachecn/apachecn-php-zh/master/docs/couchdb-php-web-dev-begin-guide/mailto:[email protected])>。
  3. 点击提交。
  4. Your browser will display the following:

What just happened?

完美的我们的表格提交正确,我们能够在网站顶部用 JSON 表示 stdClass $user。

将其提交给 Git

让我们将我们的代码提交给 Git,这样我们就可以回头看看这段代码了。

  1. 打开终端。
  2. 键入以下命令将目录更改为我们的工作目录:
    cd /Library/Webserver/Documents/verge/ 

    
  1. 向 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语句。

  1. 让我们先初始化一个 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');
    });

    
  1. 现在,让我们告诉 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。然后,我们创建了一个包含各种键和值的数组。我们选择所有这些选项的原因现在对我们来说并不重要,但我想强调前三个对象:

  1. 我们正在将 CURLOPT_URL选项设置为要将文档保存到的数据库的 URL。请记住,此语句将使用 CouchDB 的 RESTful JSON API 在 verge数据库中创建一个文档。
  2. 然后我们将 CURLOPT_POSTFIELDS设置为 $user的 JSON 编码值。这将获取我们的 JSON 字符串,并将其与 URL 一起作为数据包含。
  3. 最后,我们将 CURLOPT_HTTPHEADER设置为 array ("Content-Type: application/json"),以便确保 curl知道我们正在传递 JSON 请求。

有了选项数组集,我们需要告诉 curl实例使用它:

curl_setopt_array($curl, $options);

然后,我们使用以下两行代码执行并关闭 curl:

curl_exec($curl);
curl_close($curl);

在应用中使用此代码,我们应该能够提交表单并将其发布到 CouchDB。让我们测试一下。

  1. 打开浏览器至 http://localhost/verge/signup。
  2. 在姓名文本框中输入 John Doe,在电子邮件文本框中输入<[[email protected]](https://raw.githubusercontent.com/apachecn/apachecn-php-zh/master/docs/couchdb-php-web-dev-begin-guide/mailto:[email protected])>。
  3. 点击提交。
  4. Your browser will display the following:

What just happened?

和以前一样,它运行良好,没有任何错误。但这一次,应该创建一个 CouchDB 文档。让我们检查一下文档是否使用 Futon 正确创建。

  1. 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 your ID and rev will be different from mine:

What just happened?

  1. 单击文档,以便查看详细信息。
  2. The data in your document should match up to the information that we passed in using our curl session. Notice that type, email, and name were all set properly, and that CouchDB set _id and _rev for us.

What just happened?

将其提交给 Git

让我们将代码提交给 Git,以便将来可以再次引用此代码。

  1. 打开终端。
  2. 键入以下命令将目录更改为我们的工作目录:
    cd /Library/Webserver/Documents/verge/

    
  1. 向 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 使建立第三方库变得非常容易,并允许我们在新版本可用时进行更新。

  1. 打开终端。
  2. 键入以下命令以确保您在工作目录中:
    cd /Library/Webserver/Documents/verge/ 

    
  1. 使用 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非常简单。让我们一起走过它!

  1. 在我们的工作目录中打开 lib/bones.php,并在我们班的顶部添加以下行:
    <?php
    define('ROOT', __DIR__ . '/..');
    require_once ROOT . '/lib/sag/src/Sag.php'; 

    
  1. 我们需要确保 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 方法允许您使用它传递数据,因此触发起来非常容易。

让我们再次快速完成注册过程:

  1. 打开浏览器至 http://localhost/verge/signup。
  2. 在名称文本框中输入新名称,在电子邮件文本框中输入新电子邮件。
  3. 点击提交。

CouchDB 中创建了一个新文档,所以让我们检查 Futon 以确保它在那里:

  1. 打开浏览器至 http://localhost:5984/_utils/database.html?verge,查看 verge 数据库。
  2. 单击列表中的第二个文档。
  3. 查看这个新文档的详细信息,您将看到它与我们制作的第一个文档具有相同的结构。

完美的结果与我们的快速脏卷曲脚本完全一样,但我们的代码要简单得多,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的基类,所有类都将继承该基类。

  1. 首先,我们创建一个名为 base.php的新文件,并将其放置在工作目录(/Library/Webserver/Documents/verge/classes/base.php中)的 classes 文件夹中
  2. 在 base.php中创建具有 __construct函数的抽象类。在对象的 __construct上,我们将 $type作为一个选项,并将其设置为一个受保护的变量,也称为 $type。
    <?php
    abstract class Base
    {
    protected $type;
    public function __construct($type)
    {
    $this->type = $type;
    }
    }

    
  1. 为了便于以后在我们的类中获取和设置变量,让我们在 __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;
    } 
    }

    
  1. 每次我们将对象保存到 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类,该类将包含与用户相关的所有内容的属性和函数。

  1. 创建一个名为 user.php的新文件,并将其与 base.php一起放入 classes文件夹中。
  2. 让我们创建一个扩展 Base类的类。
    <?php
    class User extends Base
    {
    }

    
  1. 让我们将我们目前所需要的两个属性添加到我们的 User类中: name和 email。
    <?php
    class User extends Base
    {
    protected $name;
    protected $email; 
    }

    
  1. 让我们添加一个 __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对象,我们可以很容易地将其插入到应用代码中,我们应该可以启动并运行它。

  1. 打开 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);
    }

    
  1. 调整 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 表示数据非常重要。

测试一下

让我们再次快速完成注册过程,以确保一切正常:

  1. 打开浏览器至 http://localhost/verge/signup。
  2. 在名称文本框中输入新名称,在电子邮件文本框中输入新电子邮件。
  3. 点击提交。

应该在 CouchDB 中创建一个新文档。让我们检查一下蒲团,确保它在那里:

  1. 打开浏览器至 http://localhost:5984/_utils/database.html?verge查看 verge 数据库。
  2. 单击列表中的第三个文档
  3. 查看这个新文档的详细信息,您将看到它与我们制作的前两个文档具有相同的结构。

完美的一切都像以前一样工作,但我们现在使用的是一个更优雅的解决方案,我们将能够在未来的章节中构建它。

将其提交给 Git

让我们将代码提交给 Git,这样我们就可以跟踪到目前为止的进度:

  1. 打开终端。
  2. 键入以下命令将目录更改为我们的工作目录:
    cd /Library/Webserver/Documents/verge/ 

    
  1. 我们在 classes文件夹中添加了一些新文件。所以,让我们确保将这些文件添加到 Git。
    git add classes/* 

    
  1. 向 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 构建大多数应用所具有的标准注册和登录过程。伸出你的打字手指,给自己弄一杯美味的大杯咖啡,因为我们就要有真正的乐趣了。