教程 - 基础¶
概览¶
在本教程中,我们将创建一个带有简单注册表单的应用程序,同时介绍 Phalcon 的主要设计方面。
本教程涵盖了简单的 MVC 应用程序的实现,展示了使用 Phalcon 完成它的速度和简便性。开发完成后,您可以使用并扩展此应用程序以满足您的需求。本教程中的代码也可以作为学习其他 Phalcon 特定概念和想法的游乐场。
如果您只想快速开始,可以跳过这一步,并使用我们的工具自动创建一个 Phalcon 项目。开发者工具.
使用本指南的最佳方法是跟随并尝试享受乐趣。您可以获取完整的代码点击这里。如果您遇到问题或有疑问,请访问我们的社区Discord或者在我们的论坛上提问。讨论.
文件结构¶
Phalcon 的一个关键特性是它松散耦合。因此,您可以使用任何适合您的目录结构。在本教程中,我们将使用标准目录结构,通常用于 MVC 应用程序。
.
└── tutorial
├── src
│ ├── controllers
│ │ ├── IndexController.php
│ │ └── SignupController.php
│ ├── models
│ │ └── Users.php
│ └── views
└── public
├── css
├── img
├── index.php
└── js
注意
由于 Phalcon 暴露的所有代码都封装在扩展中(您已经在 Web 服务器上加载了该扩展),您不会看到vendor
包含 Phalcon 代码的目录。您需要的一切都在内存中。如果您尚未安装应用程序,请前往安装页面并在继续此教程之前完成安装。
如果这些内容完全新,请推荐您安装Phalcon Devtools也。DevTools 利用 PHP 内置的 Web 服务器,允许您几乎立即运行您的应用程序。如果选择此选项,则需要在项目的根目录下创建一个.htrouter.php
文件,内容如下:
<?php
$uri = urldecode(
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);
if ($uri !== '/' && file_exists(__DIR__ . '/public' . $uri)) {
return false;
}
$_GET['_url'] = $_SERVER['REQUEST_URI'];
require_once __DIR__ . '/public/index.php';
对于我们的教程来说,这个文件必须位于tutorial
目录下。
您还可以使用 Nginx、Apache、Cherokee 或其他 Web 服务器。您可以查看Web 服务器设置页面获取相关指令。
引导程序¶
需要创建的第一个文件是引导文件。该文件充当应用程序的入口点和配置文件。在此文件中,您可以实现组件的初始化以及定义应用程序行为。
该文件处理三件事:- 注册组件自动加载器 - 配置服务并将它们注册到依赖注入上下文中 - 解析应用程序的 HTTP 请求
自动加载器¶
我们将使用Phalcon\Autoload\Loader a PSR-4兼容文件加载器。通常应添加到自动加载器的内容包括您的控制器和模型。您还可以注册目录,以便扫描应用程序所需的文件。
首先,让我们使用controllers
和models
注册我们应用的目录。Phalcon\Autoload\Loader:
public/index.php
<?php
use Phalcon\Autoload\Loader;
define('BASE_PATH', dirname(__DIR__ . '/..'));
define('APP_PATH', BASE_PATH . '/app');
// ...
$loader = new Loader();
$loader->setDirectories(
[
APP_PATH . '/controllers/',
APP_PATH . '/models/',
]
);
$loader->register();
依赖管理¶
由于 Phalcon 是松散耦合的,服务通过框架的依赖管理器注册,以便它们可以自动注入到组件和服务中,这些组件和服务被包装在控制反转 (IoC)容器中。您经常会遇到 DI(依赖注入)这个词。依赖注入和控制反转 (IoC) 可能听起来复杂,但 Phalcon 确保它们的使用简单、实用且高效。Phalcon 的 IoC 容器由以下概念组成:- 服务容器:一个“包”,我们在其中全局存储应用程序正常运行所需的服务。- 服务或组件:将被注入到组件中的数据处理对象。
每次框架需要某个组件或服务时,都会向容器询问使用约定名称的服务。这样我们可以轻松获取应用程序所需的对象,如日志记录器、数据库连接等。
注意
如果您对细节感兴趣,请参阅Martin Fowler的这篇文章。此外,我们有一个涵盖许多使用场景的很棒的教程。
默认工厂¶
The Phalcon\Di\FactoryDefault是Phalcon\Di\Di的变体。为了简化操作,它会自动注册大多数应用程序所需的标准组件,并随 Phalcon 提供。尽管建议手动设置服务,但您可以最初使用Phalcon\Di\FactoryDefault容器,然后根据需要进行自定义。
服务可以通过多种方式注册,但在本教程中,我们将使用匿名函数:
public/index.php
现在我们需要注册视图服务,并设置框架查找视图文件的目录。由于视图不对应类,因此它们无法被我们的自动加载器自动加载。
public/index.php
<?php
use Phalcon\Mvc\View;
// ...
$container->set(
'view',
function () {
$view = new View();
$view->setViewsDir(APP_PATH . '/views/');
return $view;
}
);
现在我们需要注册一个基础 URI,这将提供 Phalcon 创建所有 URI 的功能。该组件将确保无论您是在顶级目录还是子目录中运行应用程序,所有 URI 都将是正确的。对于本教程,我们的基础路径是/
. 这在本教程的后面部分会变得很重要,当我们使用该类时。Phalcon\Tag
生成超链接。
public/index.php
<?php
use Phalcon\Mvc\Url;
// ...
$container->set(
'url',
function () {
$url = new Url();
$url->setBaseUri('/');
return $url;
}
);
处理应用程序请求¶
为了处理任何请求,Phalcon\Mvc\Application对象为我们完成所有繁重的工作。该组件将接受用户的请求,检测路由分发控制器,并呈现视图返回结果。
public/index.php
<?php
use Phalcon\Mvc\Application;
// ...
$application = new Application($container);
$response = $application->handle(
$_SERVER["REQUEST_URI"]
);
$response->send();
将一切整合在一起¶
The tutorial/public/index.php
文件应该看起来像:
public/index.php
<?php
use Phalcon\Di\FactoryDefault;
use Phalcon\Autoload\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Application;
use Phalcon\Url;
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');
$loader = new Loader();
$loader->setDirectories(
[
APP_PATH . '/controllers/',
APP_PATH . '/models/',
]
);
$loader->register();
$container = new FactoryDefault();
$container->set(
'view',
function () {
$view = new View();
$view->setViewsDir(APP_PATH . '/views/');
return $view;
}
);
$container->set(
'url',
function () {
$url = new Url();
$url->setBaseUri('/');
return $url;
}
);
$application = new Application($container);
try {
// Handle the request
$response = $application->handle(
$_SERVER["REQUEST_URI"]
);
$response->send();
} catch (\Exception $e) {
echo 'Exception: ', $e->getMessage();
}
注意
在本教程文件中,来自我们的GitHub仓库,为了在容器中注册服务,我们使用数组表示法即。DI
如你所见,引导文件非常短小,我们不需要包含任何其他文件。你已经成功地在不到30行代码的情况下创建了一个灵活的MVC应用程序。$container['url'] = ....
.
As you can see, the bootstrap file is very short, and we do not need to include any additional files. You are well on your way to creating a flexible MVC application in less than 30 lines of code.
创建控制器¶
默认情况下,Phalcon 将寻找一个名为IndexController
的控制器。它是当没有控制器或动作被添加到请求(例如)时的起点。https://localhost/
。一个IndexController
和它的IndexAction
应该类似于以下示例:
app/controllers/IndexController.php
<?php
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
public function indexAction()
{
return '<h1>Hello!</h1>';
}
}
控制器类必须具有后缀Controller
而控制器动作必须具有后缀Action
。欲了解更多信息,可以阅读我们的文档关于控制器。如果你从浏览器访问应用程序,你应该看到类似以下的内容:
注意
恭喜,你正在使用Phalcon飞行!
向视图发送输出¶
从控制器向屏幕发送输出有时是必要的,但并不理想,因为大多数MVC社区中的纯粹主义者都会证明这一点。必须将所有内容传递给负责在屏幕上输出数据的视图。Phalcon将查找与最后一个执行的动作同名的视图,位于以最后一个执行的控制器命名的目录内。
因此,在我们的情况下,如果URL为:
将调用IndexController
和indexAction
,并且它将搜索视图:
如果找到,它将解析并将其输出到屏幕上。然后,我们的视图将具有以下内容:
app/views/index/index.phtml
由于我们将echo
从控制器操作移动到了视图,现在它将是空的:
app/controllers/IndexController.php
<?php
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
public function indexAction()
{
}
}
浏览器输出将保持不变。组件在动作执行结束时自动创建。你可以阅读更多关于Phalcon中的视图的信息Phalcon\Mvc\View
component is automatically created when the action execution has ended. You can read more about views in Phalcon 点击这里.
设计注册表单¶
现在我们将更改index.phtml
视图文件,以添加一个链接到一个新控制器名称注册。目标是允许用户注册到我们的应用程序。
app/views/index/index.phtml
<?php
echo "<h1>Hello!</h1>";
echo PHP_EOL;
echo PHP_EOL;
echo $this->tag->a('signup', 'Sign Up Here!');
生成的HTML代码显示一个锚点(<a>
)HTML标签链接到一个新的控制器:
app/views/index/index.phtml
(渲染)
为了生成<a>
标签的链接,我们使用Phalcon\Html\TagFactory组件。这是一个实用类,提供了一种轻松构建符合框架约定的HTML标签的方法。此类还作为依赖注入容器中的服务注册,因此我们可以使用$this->tag
来访问其功能。
注意
Phalcon\Html\TagFactory
已经在DI容器中注册,因为我们使用了Phalcon\Di\FactoryDefault
容器。如果你手动注册了所有服务,则需要在此容器中注册该组件,以便使其在你的应用程序中可用。
并且注册控制器为(app/controllers/SignupController.php
):
app/controllers/SignupController.php
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
}
空的索引操作给予干净的通过到包含表单定义的视图(app/views/signup/index.phtml
):
app/views/signup/index.phtml
<h2>Sign up using this form</h2>
<?php echo $this->tag->form(["action" => "signup/register"]); ?>
<p>
<label for="name">Name</label>
<?php echo $this->tag->inputText("name"); ?>
</p>
<p>
<label for="email">E-Mail</label>
<?php echo $this->tag->inputText("email"); ?>
</p>
<p>
<?php echo $this->tag->inputSubmit("Register"); ?>
</p>
<?php echo $this->tag->close('form'); ?>
在你的浏览器中查看表单将显示以下内容:
正如上文所述,Phalcon\Html\TagFactory实用类,提供了便捷的方法让你轻松构建表单HTML元素。方法接收一组键值对数组来设置表单,例如应用程序中的相对URI到控制器/动作。创建了一个文本HTML元素,其名称为传递的参数,而则创建了一个提交HTML按钮。最后,调用将关闭我们的标签。form()
method receives an array of key/value pairs that set up the form, for example, a relative URI to a controller/action in the application. The inputText()
creates a text HTML element with the name as the passed parameter, while the inputSubmit()
creates a submit HTML button. Finally, a call to close()
will close our <form>
tag.
点击注册按钮,你会注意到框架抛出的一个异常,指出我们在控制器中缺少动作。我们的文件抛出这个异常:register
action in the controller signup
. Our public/index.php
file throws this exception:
实现该方法将移除该异常:
app/controllers/SignupController.php
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
public function registerAction()
{
}
}
如果你再次点击注册按钮,你会看到一个空白页。我们稍后将会添加一个视图提供有用的反馈。但是首先,我们应该致力于将用户的输入存储到数据库中的代码。
根据MVC指南,数据库交互必须通过模型进行,以确保清洁、面向对象的代码。
创建模型¶
Phalcon带来了第一个完全用C语言编写的PHP ORM。它不仅没有增加开发的复杂性,反而简化了它。
在创建我们的第一个模型之前,我们需要使用数据库访问工具或数据库命令行实用程序创建一个数据库表。在这个教程中,我们使用MySQL作为我们的数据库。一个简单的表来存储注册用户可以这样创建:
create_users_table.sql
CREATE TABLE `users`
(
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Record ID',
`name` varchar(255) NOT NULL COMMENT 'User Name',
`email` varchar(255) NOT NULL COMMENT 'User Email Address',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
模型应位于app/models
目录(app/models/Users.php
)。模型映射到用户表:
app/models/Users.php
注意
请注意,模型的公共属性对应于我们表中的字段名称。
设置数据库连接¶
为了使用数据库连接并通过我们的模型访问数据,我们需要在引导过程中指定它。数据库连接只是我们应用程序的另一个服务,可以在整个应用程序中使用:
public/index.php
<?php
use Phalcon\Db\Adapter\Pdo\Mysql;
$container->set(
'db',
function () {
return new Mysql(
[
'host' => '127.0.0.1',
'username' => 'root',
'password' => 'secret',
'dbname' => 'tutorial',
]
);
}
);
根据你的数据库调整上面的代码片段。
使用正确的数据库参数,我们的模型已准备好与其他应用程序部分进行交互,因此我们可以保存用户的输入。首先,让我们花一点时间创建一个视图用于...SignupController::registerAction()
这将显示一条消息,告知用户操作的结果保存操作。
app/views/signup/register.phtml
<div class="alert alert-<?php echo $success === true ? 'success' : 'danger'; ?>">
<?php echo $message; ?>
</div>
<?php echo $this->tag->a('/', 'Go back', ['class' => 'btn btn-primary']); ?>
使用模型存储数据¶
app/controllers/SignupController.php
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
public function registerAction()
{
$post = $this->request->getPost();
// Store and check for errors
$user = new Users();
$user->name = $post['name'];
$user->email = $post['email'];
// Store and check for errors
$success = $user->save();
// passing the result to the view
$this->view->success = $success;
if ($success) {
$message = "Thanks for registering!";
} else {
$message = "Sorry, the following problems were generated:<br>"
. implode('<br>', $user->getMessages());
}
// passing a message to the view
$this->view->message = $message;
}
}
在registerAction
开始时,我们使用Users
类创建了一个空的用户对象。我们将使用这个类来管理用户的记录。正如上面提到的,类的公共属性映射到数据库表中的字段。在新记录中设置相关值并调用users
table in our database. Setting the relevant values in the new record and calling save()
将把该记录的数据存储到数据库中。该save()
方法返回一个boolean
值,表示保存是否成功。
ORM会自动转义输入以防止SQL注入,因此我们只需要将请求传递给save()
方法设置容器。
额外的验证会在定义为非空(必填)的字段上自动进行。如果我们没有在注册表单中填写任何必填字段,我们的屏幕将会如下所示:
列出已注册的用户¶
现在我们需要获取并显示数据库中所有已注册的用户
我们在indexAction
的IndexController
第一件事是显示搜索所有用户的結果,这可以通过简单地调用静态方法find()
来完成(在我们的模型上)Users::find()
)。
indexAction
将会发生如下变化:
app/controllers/IndexController.php
<?php
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
/**
* Welcome and user list
*/
public function indexAction()
{
$this->view->users = Users::find();
}
}
注意
我们将find
的结果分配给view
对象的一个魔术属性。这将用分配的数据设置此变量,并使其在我们的视图中可用
在我们的视图文件views/index/index.phtml
中,我们可以这样使用$users
变量:
视图将如下所示:
views/index/index.phtml
<?php
echo "<h1>Hello!</h1>";
echo $this->tag->a('signup', 'Sign Up Here!', ['class' => 'btn btn-primary']);
if ($users->count() > 0) {
?>
<table class="table table-bordered table-hover">
<thead class="thead-light">
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">Users quantity: <?php echo $users->count(); ?></td>
</tr>
</tfoot>
<tbody>
<?php foreach ($users as $user) { ?>
<tr>
<td><?php echo $user->id; ?></td>
<td><?php echo $user->name; ?></td>
<td><?php echo $user->email; ?></td>
</tr>
<?php } ?>
</tbody>
</table>
<?php
}
如您所见,我们的变量$users
可以被迭代和计数。您可以从我们的文档中关于模型.
样式¶
现在我们可以给我们的应用程序添加一些小的设计元素。我们可以在代码中添加Bootstrap CSS以便在整个视图中使用。我们将在index.phtml
文件夹中添加一个views
文件,其内容如下:
app/views/index.phtml
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Phalcon Tutorial</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<?php echo $this->getContent(); ?>
</div>
</body>
</html>
在上面的模板中,最重要的一行是对getContent()
方法的调用。此方法返回从我们的视图生成的所有内容。我们的应用程序现在将显示:
结论¶
如您所见,使用Phalcon构建应用程序非常容易。由于Phalcon是一个加载到内存中的扩展,您的项目的占用空间将很小,同时您还将享受性能提升的好处。
如果您想了解更多,请查看Vökuró教程下一篇。