blob: 6cdcf746378fb17a1e01d38af747f651e0ca3342 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= 使用 PHP 创建数据库驱动的应用程序
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: 使用 PHP 创建数据库驱动的应用程序 - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, 使用 PHP 创建数据库驱动的应用程序
= 6 课:在数据库中添加新的愿望
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: 6 课:在数据库中添加新的愿望 - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, 6 课:在数据库中添加新的愿望
在本课中,将使用以下两个功能扩展应用程序功能:
要实现该功能,请编辑 `editWishList.php` 文件并创建新文件 `editWish.php`
image::images/page-flow-diagram-l6.png[]
当前文档是link:wish-list-tutorial-main-page.html[+在适用于 PHP NetBeans IDE 中创建 CRUD 应用程序+]教程的一部分。
[[_application_source_code_from_the_previous_lesson]]
== 来自上一课的应用程序源代码
MySQL 用户:单击link:https://netbeans.org/files/documents/4/1931/lesson5.zip[+此处+]以下载源代码,该代码反映了在完成上一课之后的项目状态。
Oracle 数据库用户:单击link:https://netbeans.org/projects/www/downloads/download/php%252Foracle-lesson5.zip[+此处+]以下载源代码,该代码反映了在完成上一课之后的项目状态。
[[_submitting_a_new_wish]]
== 提交新的愿望
用户可使用以下步骤提交新的愿望:
1. 用户进行登录,切换到 `editWishList.php` 页,然后按 "Add Wish" 按钮。 `editWish.php` 页打开,并显示 HTML 窗体。
2. 用户在 HTML 窗体中输入愿望说明,可能还会输入他/她希望实现愿望的日期,然后按 "Save Changes" 按钮。
3. 如果提交窗体而未输入愿望说明,用户将返回到窗体进行重试。如果用户提交了截止日期而没有提供说明,在重新加载窗体时,将重新显示该日期。
要为用户实现此过程,请在应用程序中添加以下功能:
* <<add-wish-ui-elements,用户界面组件>>,包含添加愿望的 HTML 窗体以及 `editWishList.php ` 中将用户重定向到该窗体的按钮。
* 在提交不完整的窗体时<<_returning_to_the_front_index_php_page,重新显示截止日期>>的代码。
[[add-wish-ui-elements]]
=== 添加用户界面组件
*添加功能以添加新的愿望:*
1. 实现 "Add Wish" 按钮。在 `editWishList.php` 文件的 PHP 块下面添加以下 HTML 代码:
[source,xml]
----
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<form name="addNewWish" action="editWish.php">
<input type="submit" value="Add Wish">
</form>
</body>
</html>
----
*注:*您可以忽略来自 HTML 验证器的警告。
窗体包含 `submit` 类型的 "Add Wish" 输入字段。该字段实现 "Add Wish" 按钮。当用户单击 "Add Wish" 时,他们将重定向到 `editWish.php` 页。由于没有通过该窗体传输任何数据,因此,不会使用服务器请求方法。
[start=2]
. addNewWish 窗体上面添加一个表以显示许愿者的现有愿望。代码类似于 `wishlist.php`
*对于 MySQL 数据库*:
[source,php]
----
<table border="black">
<tr>
<th>Item</th>
<th>Due Date</th>
</tr>
<?php
$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
while ($row = mysqli_fetch_array($result)) {
echo "<tr><td>" . htmlentities($row['description']) . "</td>";
echo "<td>" . htmlentities($row['due_date']) . "</td></tr>\n";
}
mysqli_free_result($result);
?>
</table>
----
*对于 Oracle 数据库:*
[source,php]
----
<table border="black">
<tr>
<th>Item</th>
<th>Due Date</th>
</tr>
<?php
$stid = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
while ($row = oci_fetch_array($stid)) {
echo "<tr><td>" . htmlentities($row['DESCRIPTION']) . "</td>";
echo "<td>" . htmlentities($row['DUE_DATE']) . "</td></tr>\n";
}
oci_free_statement($stid);
?>
</table>
----
[start=3]
. "Source Files"(源文件)文件夹中创建 `editWish.php` PHP 文件。
[start=4]
. `editWish.php` 中,实现 "Add Wish" 窗体。在 <? php ?> 块下键入或粘贴以下代码:
[source,xml]
----
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<form name="editWish" action="editWish.php" method="POST">
Describe your wish: <input type="text" name="wish" value="" /><br/>
When do you want to get it? <input type="text" name="dueDate" value=""/><br/>
<input type="submit" name="saveWish" value="Save Changes"/>
<input type="submit" name="back" value="Back to the List"/>
</form>
</body>
</html>
----
"Add Wish" 窗体包含:
* 两个空文本字段,用于输入愿望说明和截止日期。
* 在输入字段旁边输出的文本。
* 表示 "Save Changes" 按钮的 `submit` 字段
* 表示 "Back to the List" 按钮的 `submit` 字段,用于返回到 `editWishList.php`
在按 "Add Wish" 按钮后,窗体将通过请求方法 POST 将输入的数据提交到同一页面,即 `editWish.php`
[[_redisplaying_the_due_date_after_an_unsuccessful_submission]]
=== 在提交失败后重新显示截止日期
如果用户在 "Add Wish" 窗体中未填写说明,则会显示一条错误消息,并且用户会返回到 `editWish.php` 页。当用户返回到 `editWish.php` 时,"Add Wish" 窗体应显示 `dueDate` 值(如果已输入)。在当前的窗体实现中,这两个字段始终为空。要保留输入的值,您需要将新愿望数据保存到数组中。该数组包含两个名为 `description` `due_date` 的元素。然后,您需要更改 "Add Wish" 窗体,使其能够从数组中检索 `dueDate` 字段值。
*注:*未输入说明时,重新加载输入窗体的代码包含在<<_verifying_the_wisher_s_logon,用于验证数据并将其输入到数据库的代码>>中。本部分未介绍该代码。本部分中的代码仅保留 `dueDate` 值,以便在重新加载窗体时显示该值。
*在用户提交输入窗体失败后重新显示该窗体:*
1. `editWish.php` HTML <body> 元素内,紧靠输入窗体上面键入或粘贴以下代码块:
[source,php]
----
<?php
if ($_SERVER['REQUEST_METHOD'] == "POST")
$wish = array("description" => $_POST['wish'],
"due_date" => $_POST['dueDate']);
else
$wish = array("description" => "",
"due_date" => "");
?>
----
该代码检查使用哪个请求服务器方法传输数据,并创建一个名为 $wish 的数组。如果该方法是 POST(表示在尝试保存具有空说明的愿望失败后显示输入窗体),则 `description` `due_date` 元素接受通过 POST 传输的值。
如果该方法不是 POST(表示在重定向窗体后第一次显示输入窗体),则 `editWishList.php` 页以及 `description` `due_date` 元素均为空。
*注:*在这两种情况下,说明均为空。唯一的区别是 `dueDate`
[start=2]
. 更新 "Add Wish" 窗体,以便从 `$wish` 数组中检索其输入字段的值。将 "Add Wish" 窗体中的行:
[source,php]
----
Describe your wish: <input type="text" name="wish" value="" /><br/>
When do you want to get it? <input type="text" name="dueDate" value=""/><br/>
----
替换为:
[source,php]
----
Describe your wish: <input type="text" name="wish" value="<?php echo $wish['description'];?>" /><br/>
When do you want to get it? <input type="text" name="dueDate" value="<?php echo $wish['due_date']; ?>"/><br/>
----
[[_verifying_the_wisher_s_logon]]
== 验证许愿者的登录
`editWish.php` 文件中,在文件顶部的 <? php ?> 块中输入以下会话处理代码:
[source,php]
----
session_start();
if (!array_key_exists("user", $_SESSION)) {
header('Location: index.php');
exit;
}
----
该代码将会:
* 打开 $_SESSION 数组以检索数据。
* 验证 $_SESSION 数组是否包含具有标识符 "user" 的元素。
* 如果检查失败(表示用户未登录),则将应用程序重定向到主页 index.php 并取消 PHP 处理。
要检查会话处理是否正常工作,请从 IDE 中运行 editWish.php 文件。index.php 页打开,因为没有通过会话将用户传输到 editWish.page
[[insert-new-wish]]
== 在数据库中插入新的愿望
在用户提交新的愿望后,应用程序需要将愿望添加到“愿望”数据库中。要实现该功能,请在应用程序中添加以下代码:
* `db.php` `WishDB` 类中添加另外两个辅助函数。
* 一个函数将新记录添加到 wishes 表中。
* 另一个函数将日期转换为 MySQL 数据库服务器支持的格式。
* `editWish.php` 中添加代码,以使用 `WishDB` 中的新辅助函数在数据库中输入新的愿望。
[[add-insert-wish]]
=== insert_wish 函数添加到 WishDB
该函数要求将许愿者 ID、新愿望说明和愿望截止日期作为输入参数,并在数据库的新记录中输入该数据。该函数不会返回任何值。
打开 `db.php ` 并将 `insert_wish` 函数添加到 `WishDB` 类中:
*对于 MySQL 数据库:*
[source,php]
----
function insert_wish($wisherID, $description, $duedate) {
$description = $this->real_escape_string($description);
if ($this->format_date_for_sql($duedate)==null){
$this->query("INSERT INTO wishes (wisher_id, description)" .
" VALUES (" . $wisherID . ", '" . $description . "')");
} else
$this->query("INSERT INTO wishes (wisher_id, description, due_date)" .
" VALUES (" . $wisherID . ", '" . $description . "', "
. $this->format_date_for_sql($duedate) . ")");
}
----
*对于 Oracle 数据库:*
[source,php]
----
function insert_wish($wisherID, $description, $duedate) {
$query = "INSERT INTO wishes (wisher_id, description, due_date) VALUES (:wisher_id_bv, :desc_bv, to_date(:due_date_bv, 'YYYY-MM-DD'))";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ':wisher_id_bv', $wisherID);
oci_bind_by_name($stid, ':desc_bv', $description);
oci_bind_by_name($stid, ':due_date_bv', $this->format_date_for_sql($duedate));
oci_execute($stid);
oci_free_statement($stid);
}
----
该代码调用 format_date_for_sql 函数,以将输入的截止日期转换为数据库服务器可以处理的格式。然后,执行 INSERT INTO wishes (wisher_id, description, due_date) 查询以在数据库中输入新的愿望。
[[add-format-date-for-sql]]
=== format_date_for_sql 函数添加到 WishDB
`format_date_for_sql` 函数添加到 `db.php` `WishDB` 类中。该函数需要一个字符串,并将日期作为输入参数。该函数返回具有数据库服务器可处理的格式的日期;如果输入字符串为空,则返回 `空值`
*注:*本示例中的函数使用 PHP `date_parse` 函数。该函数仅适用于英语语言的日期(如 December 25, 2010)和阿拉伯数字。专业 Web 站点使用日期选取器。
*对于 MySQL 数据库:*
[source,php]
----
function format_date_for_sql($date) {
if ($date == "")
return null;
else {
$dateParts = date_parse($date);
return $dateParts["year"] * 10000 + $dateParts["month"] * 100 + $dateParts["day"];
}
}
*对于 Oracle 数据库:*
[source,php]
----
function format_date_for_sql($date) {
if ($date == "")
return null;
else {
$dateParts = date_parse($date);
return $dateParts['year'] * 10000 + '-' + $dateParts['month'] * 100 + '-' + $dateParts['day'];
}
}
----
如果输入字符串为空,则代码返回空值。否则,将 `$date` 作为输入参数以调用内部 `date_parse` 函数。 `date_parse` 函数返回一个数组,其中包含三个名为 `$dateParts["year"]` `$dateParts["month"]` `$dateParts["day"]` 的元素。最终输出字符串由 `$dateParts` 数组元素组成。
*重要说明:* `date_parse` 函数仅识别英语日期。例如,它解析 "February 2, 2016" 而不解析 "2 Unora, 2016"
*Oracle 数据库用户注意事项:*唯一的格式要求是, `return $dateParts...` 语句中的日期格式应与 `insert_wish` 查询的 `to_date` SQL 函数中的日期格式相匹配。
[[validateAndEnterWishToDatabase]]
=== 在数据库中输入新的愿望记录
现在,您已开发了辅助函数,接下来便可添加代码以验证新的愿望数据;如果数据有效,则将数据输入到数据库中。如果数据无效,代码必须重新加载 "Add Wish" 窗体。如果数据无效的原因是没有输入说明,但输入了截止日期,则会保存截止日期并在重新加载窗体时重新显示该日期,您<<_returning_to_the_front_index_php_page,以前开发的>>代码实现了该功能。
在顶部 <? php?> 块(属于 `editWish.php` )中会话处理代码下面输入以下代码:
[source,php]
----
require_once("Includes/db.php");
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_SESSION['user']);
$wishDescriptionIsEmpty = false;
if ($_SERVER['REQUEST_METHOD'] == "POST"){
if (array_key_exists("back", $_POST)) {
header('Location: editWishList.php' );
exit;
} else
if ($_POST['wish'] == "") {
$wishDescriptionIsEmpty = true;
} else {
WishDB::getInstance()->insert_wish($wisherID, $_POST['wish'], $_POST['dueDate']);
header('Location: editWishList.php' );
exit;
}
}
----
该代码执行以下功能:
* 允许使用 `db.php` 文件
* 获取或创建 `WishDB` 类实例
* 通过调用 `get_wisher_id_by_name` 函数,检索尝试添加愿望的许愿者的 ID
* 初始化 `$wishDescriptionIsEmpty` 标志,该标志将在以后显示错误消息时使用。
* 检查请求方法是否为 POST,这意味着数据是从窗体中提交的,目的是在 `editWish.php` 页中输入愿望数据。
* 检查 `$_POST` 数组是否包含具有 "back" 键的元素
如果 `$_POST` 数组包含具有 "back" 键的元素,则在提交窗体之前按了 "Back to the List" 按钮。在这种情况下,代码会将用户重定向到 `editWishList.php` ,而不保存在字段中输入的任何数据并停止 PHP 处理。
如果 $_POST 数组__包含具有 "back" 键的元素,则数据是通过按 "Save Changes" 按钮提交的。在这种情况下,代码验证是否填写了愿望说明。该代码的工作方式是,检查 $_POST 数组中具有 "wish" 键的元素是否为空;如果该键为空,则将 $wishDescriptionIsEmpty 标志更改为 true。请注意,不会在 PHP 块中执行其他代码,将重新加载 "Add Wish" 窗体。
如果未按 "Back to the List" 按钮但填写了愿望说明,代码将调用 `insert_wish` 函数并将许愿者 ID、说明和愿望截止日期作为输入参数。然后,代码将用户重定向到 `editWishList.php` 页并停止 PHP 处理。
[[_displaying_error_messages]]
=== 显示错误消息
如果用户尝试保存愿望,但没有输入愿望说明,则一定会显示错误消息。
HTML 输入窗体的 "Describe your wish" 输入字段下输入以下 <? php?> 块:
[source,php]
----
<?php
if ($wishDescriptionIsEmpty)
echo "Please enter description<br/>";
?>
----
如果 `$wishDescriptionIsEmpty` 标志为 true,则会显示错误消息。该标志是在输入窗体验证期间处理的。
[[_returning_to_the_front_index_php_page]]
== 返回到主页 index.php
用户应该能够随时按某个按钮返回到应用程序主页。
要实现该功能,请在 `editWishList.php` 文件中的结束 </body> 标记前面输入以下 HTML 输入窗体:
[source,xml]
----
<form name="backToMainPage" action="index.php"><input type="submit" value="Back To Main Page"/></form>
----
一按下 "Back to Main Page" 按钮,该窗体便将用户重定向到主页 index.php
[[_testing_the_add_wish_functionality]]
== 测试添加愿望功能
1. 运行应用程序。在 `index.php` 页上,填写以下字段:在 "Username" 字段中输入 "Tom",在 "Password" 字段中输入 "tomcat"
image::images/user-logon-to-edit-wish-list.png[]
[start=2]
. "Edit My Wish List" 按钮。 `editWishList.php` 页打开。
image::images/edit-wish-list-add-wish.png[]
[start=3]
. "Back to Main Page" 按钮。 `index.php` 页打开。
[start=4]
. Tom 身份登录,然后再次按 "Edit My Wish List" 按钮。 `editWishList.php` 页打开。
[start=5]
. "Add Wish" 按钮。 `editWish.php` 页打开。填写窗体。
image::images/new-wish.png[]
"Back to the List" 按钮。 `editWishList.php` 页打开,但未添加输入的愿望。
[start=6]
. 再次按 "Add Wish" 按钮。 `editWish.php` 页打开。填写截止日期并将说明保留空白。按 "Save Changes" 按钮。 `editWish.php` 页将显示输入窗体,其中包含一条错误消息和填写的截止日期。
[start=7]
. 再次按 "Add Wish" 按钮。 `editWish.php` 页打开。填写窗体,然后按 "Save Changes" 按钮。 `editWishList.php` 页将显示更新的愿望列表。
image::images/edit-wish-list-updated.png[]
[[_application_source_code_after_the_current_lesson_is_completed]]
== 完成当前课程后的应用程序源代码
MySQL 用户:单击link:https://netbeans.org/files/documents/4/1932/lesson6.zip[+此处+]以下载源代码,该代码反映了在完成课程后的项目状态。
Oracle 数据库用户:单击link:https://netbeans.org/projects/www/downloads/download/php%252Foracle-lesson6.zip[+此处+]以下载源代码,该代码反映了在完成课程后的项目状态。
[[_next_steps]]
== 后续步骤
link:wish-list-lesson5.html[+<< 上一课+]
link:wish-list-lesson7.html[+下一课 >>+]
link:wish-list-tutorial-main-page.html[+返回到教程主页+]
link:/about/contact_form.html?to=3&subject=Feedback:%20PHP%20Wish%20List%20CRUD%206:%20Writing%20New%20DB%20Entry[+发送有关此教程的反馈意见+]
要发送意见和建议、获得支持以及随时了解 NetBeans IDE PHP 开发功能的最新开发情况,请link:../../../community/lists/top.html[+加入 users@php.netbeans.org 邮件列表+]。
link:../../trails/php.html[+返回至 PHP 学习资源+]