Sections

教程-基本

Throughout this tutorial, we’ll walk you through the creation of an application with a simple registration form from the ground up. The following guide is to provided to introduce you to Phalcon framework’s design aspects.

This tutorial covers the implementation of a simple MVC application, showing how fast and easy it can be done with Phalcon. This tutorial will get you started and help create an application that you can extend to address many needs. The code in this tutorial can also be used as a playground to learn other Phalcon specific concepts and ideas.

If you just want to get started you can skip this and create a Phalcon project automatically with our developer tools. (It is recommended that if you have not had experience with to come back here if you get stuck)

The best way to use this guide is to follow along and try to have fun. You can get the complete code here. If you get hung-up on something please visit us on Discord or in our Forum.

文件结构

A key feature of Phalcon is it’s loosely coupled, you can build a Phalcon project with a directory structure that is convenient for your specific application. That said some uniformity is helpful when collaborating with others, so this tutorial will use a “Standard” structure where you should feel at home if you have worked with other MVC’s in the past.

.
└── tutorial
    ├── app
    │   ├── controllers
    │   │   ├── IndexController.php
    │   │   └── SignupController.php
    │   ├── models
    │   │   └── Users.php
    │   └── views
    └── public
        ├── css
        ├── img
        ├── index.php
        └── js

Note: You will not see a `vendor` directory as all of Phalcon's core dependencies are loaded into memory via the Phalcon extension you should have installed. If you missed that part have not installed the Phalcon extension [please go back](/3.4/en/installation) and finish the installation before continuing.

If this is all brand new it is recommended that you install the Phalcon Devtools since it leverages PHP’s built-in server you to get your app running without having to configure a web server by adding this .htrouter to the root of your project.

Otherwise if you want to use Nginx here are some additional setup here.

Apache can also be used with these additional setup here.

Finally, if you flavor is Cherokee use the setup here.

启动

您需要创建的第一个文件是引导文件。 This file acts as the entry-point and configuration for your application. In this file, you can implement initialization of components as well as application behavior.

This file handles 3 things:

  • Registration of component autoloaders
  • Configuring Services and registering them with the Dependency Injection context
  • Resolving the application’s HTTP requests

自动加载

Autoloaders leverage a PSR-4 compliant file loader running through the Phalcon. Common things that should be added to the autoloader are your controllers and models. You can register directories which will search for files within the application’s namespace. If you want to read about other ways that you can use autoloaders head here.

To start, lets register our app’s controllers and models directories. Don’t forget to include the loader from Phalcon\Loader.

public/index.php

<?php

use Phalcon\Loader;

// Define some absolute path constants to aid in locating resources
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');
// ...

$loader = new Loader();

$loader->registerDirs(
    [
        APP_PATH . '/controllers/',
        APP_PATH . '/models/',
    ]
);

$loader->register();

依赖关系管理

Since Phalcon is loosely coupled, services are registered with the frameworks Dependency Manager so they can be injected automatically to components and services wrapped in the IoC container. Frequently you will encounter the term DI which stands for Dependency Injection. Dependency Injection and Inversion of Control(IoC) may sound like a complex feature but in Phalcon their use is very simple and practical. Phalcon’s IoC container consists of the following concepts:

  • Service Container: a “bag” where we globally store the services that our application needs to function.
  • Service or Component: Data processing object which will be injected into components

Each time the framework requires a component or service, it will ask the container using an agreed upon name for the service. Don’t forget to include Phalcon\Di with setting up the service container.

If you are still interested in the details please see this article by [Martin Fowler](https://martinfowler.com/articles/injection.html). Also we have [a great tutorial](/3.4/en/di) covering many use cases.

Factory Default

The Phalcon\Di\FactoryDefault is a variant of Phalcon\Di. To make things easier, it will automatically register most of the components that come with Phalcon. We recommend that you register your services manually but this has been included to help lower the barrier of entry when getting used to Dependency Management. Later, you can always specify once you become more comfortable with the concept.

Services can be registered in several ways, but for our tutorial, we’ll use an anonymous function:

public/index.php

<?php

use Phalcon\Di\FactoryDefault;

// ...

// Create a DI
$di = new FactoryDefault();

在下一部分中,我们注册表示框架在这里可以品尝意见文件的目录的”view”服务。 如意见不对应的类,它们不能自动加载。

public/index.php

<?php

use Phalcon\Mvc\View;

// ...

// Setup the view component
$di->set(
    'view',
    function () {
        $view = new View();
        $view->setViewsDir(APP_PATH . '/views/');
        return $view;
    }
);

Next, we register a base URI so that all URIs generated by Phalcon match the application’s base path of “/”. 当我们使用 Phalcon\Tag 类来生成超链接,这将成为重要稍后在本教程中。

public/index.php

<?php

use Phalcon\Mvc\Url as UrlProvider;

// ...

// Setup a base URI
$di->set(
    'url',
    function () {
        $url = new UrlProvider();
        $url->setBaseUri('/');
        return $url;
    }
);

Handling the application request

In the last part of this file, we find Phalcon\Mvc\Application. 其目的是以初始化请求环境,路由传入的请求,然后派遣任何发现的行动; 它聚合了任何响应,并将它们返回过程完成后。

public/index.php

<?php

use Phalcon\Mvc\Application;

// ...

$application = new Application($di);
$response = $application->handle();
$response->send();

Putting everything together

Tutorial/public/index.php 文件应该看起来像:

public/index.php

<?php

use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Application;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Url as UrlProvider;

// Define some absolute path constants to aid in locating resources
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');

// Register an autoloader
$loader = new Loader();

$loader->registerDirs(
    [
        APP_PATH . '/controllers/',
        APP_PATH . '/models/',
    ]
);

$loader->register();

// Create a DI
$di = new FactoryDefault();

// Setup the view component
$di->set(
    'view',
    function () {
        $view = new View();
        $view->setViewsDir(APP_PATH . '/views/');
        return $view;
    }
);

// Setup a base URI
$di->set(
    'url',
    function () {
        $url = new UrlProvider();
        $url->setBaseUri('/');
        return $url;
    }
);

$application = new Application($di);

try {
    // Handle the request
    $response = $application->handle();

    $response->send();
} catch (\Exception $e) {
    echo 'Exception: ', $e->getMessage();
}

As you can see, the bootstrap file is very short and we do not need to include any additional files. Congratulations you are well on your to having created a flexible MVC application in less than 30 lines of code.

创建控制器

By default Phalcon will look for a controller named IndexController. It is the starting point when no controller or action has been added in the request (eg. http://localhost:8000/). An IndexController and its IndexAction should resemble the following example:

app/controllers/IndexController.php

<?php

use Phalcon\Mvc\Controller;

class IndexController extends Controller
{
    public function indexAction()
    {
        echo '<h1>Hello!</h1>';
    }
}

The controller classes must have the suffix Controller and controller actions must have the suffix Action. If you access the application from your browser, you should see something like this:

Congratulations, you’re phlying with Phalcon!

将输出发送到一个视图

将输出发送到屏幕从控制器有时是必要的但不是可取大多数纯粹主义者在 MVC 社区将证明这一点。 一切必须传递给视图,它负责输出屏幕上的数据。 Phalcon将查找具有相同名称的最后一个视图执行行动作为最后一个执行控制器命名的目录里面。 在我们的例子 (app/views/index/index.phtml):

app/views/index/index.phtml

<?php echo "<h1>Hello!</h1>";

我们的控制器 (app/controllers/IndexController.php) 现在有一个空操作定义:

app/controllers/IndexController.php

<?php

use Phalcon\Mvc\Controller;

class IndexController extends Controller
{
    public function indexAction()
    {

    }
}

浏览器输出应保持不变。 Phalcon\Mvc\View 静态组件操作执行结束时自动创建。 Learn more about views usage here.

Designing a sign-up form

Now we will change the index.phtml view file, to add a link to a new controller named “signup”. The goal is to allow users to sign up within our application.

app/views/index/index.phtml

<?php

echo "<h1>Hello!</h1>";

echo PHP_EOL;

echo PHP_EOL;

echo $this->tag->linkTo(
    'signup',
    'Sign Up Here!'
);

The generated HTML code displays an anchor (<a>) HTML tag linking to a new controller:

app/views/index/index.phtml (rendered)

<h1>Hello!</h1>

<a href="/signup">Sign Up Here!</a>

若要生成标记我们使用 Phalcon\Tag 类。 这是一个实用程序类,使我们能够构建与框架公约在头脑中的 HTML 标记。 As this class is also a service registered in the DI we use $this->tag to access it.

A more detailed article regarding HTML generation can be found here.

这里是注册控制器 (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("signup/register"); ?>

    <p>
        <label for="name">Name</label>
        <?php echo $this->tag->textField("name"); ?>
    </p>

    <p>
        <label for="email">E-Mail</label>
        <?php echo $this->tag->textField("email"); ?>
    </p>

    <p>
        <?php echo $this->tag->submitButton("Register"); ?>
    </p>

</form>

在您的浏览器中查看窗体将显示这样的事情:

Phalcon\Tag also provides useful methods to build form elements.

The Phalcon\Tag::form() method receives only one parameter for instance, a relative URI to a controller/action in the application.

By clicking the “Send” button, you will notice an exception thrown from the framework, indicating that we are missing the register action in the controller signup. 我们的 public/index.php 文件会引发此异常:

例外: 行动"register"中找不到处理程序"signup"

实施这种方法将删除该异常:

app/controllers/SignupController.php

<?php

use Phalcon\Mvc\Controller;

class SignupController extends Controller
{
    public function indexAction()
    {

    }

    public function registerAction()
    {

    }
}

如果您再次单击”Send”按钮,您将看到一个空白页面。 The name and email input provided by the user should be stored in a database. 根据 MVC 的指引,必须通过模型完成数据库交互以确保干净的面向对象的代码。

创建模型

Phalcon brings the first ORM for PHP entirely written in C-language. Instead of increasing the complexity of development, it simplifies it.

Before creating our first model, we need to create a database table outside of Phalcon to map it to. A simple table to store registered users can be created like this:

create_users_table.sql

CREATE TABLE `users` (
    `id`    int(10)     unsigned NOT NULL AUTO_INCREMENT,
    `name`  varchar(70)          NOT NULL,
    `email` varchar(70)          NOT NULL,

    PRIMARY KEY (`id`)
);

A model should be located in the app/models directory (app/models/Users.php). The model maps to the “users” table:

app/models/Users.php

<?php

use Phalcon\Mvc\Model;

class Users extends Model
{
    public $id;
    public $name;
    public $email;
}

设置数据库连接

In order to use a database connection and subsequently access data through our models, we need to specify it in our bootstrap process. 数据库连接是我们应用程序的另一个服务可以用于几个组件:

public/index.php

<?php

use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;

// Setup the database service
$di->set(
    'db',
    function () {
        return new DbAdapter(
            [
                'host'     => '127.0.0.1',
                'username' => 'root',
                'password' => 'secret',
                'dbname'   => 'tutorial1',
            ]
        );
    }
);

使用正确的数据库的参数,我们的模型已作好准备工作,并与其余的应用程序进行交互。

使用模型存储数据

app/controllers/SignupController.php

<?php

use Phalcon\Mvc\Controller;

class SignupController extends Controller
{
    public function indexAction()
    {

    }

    public function registerAction()
    {
        $user = new Users();

        // Store and check for errors
        $success = $user->save(
            $this->request->getPost(),
            [
                "name",
                "email",
            ]
        );

        if ($success) {
            echo "Thanks for registering!";
        } else {
            echo "Sorry, the following problems were generated: ";

            $messages = $user->getMessages();

            foreach ($messages as $message) {
                echo $message->getMessage(), "<br/>";
            }
        }

        $this->view->disable();
    }
}

At the beginning of the registerAction we create an empty user object from the Users class, which manages a User’s record. The class’s public properties map to the fields of the users table in our database. 设置新记录中的相关值以及调用 save () 会将数据存储在数据库中为该记录。 Save () 方法返回一个布尔值,该值指示存储的数据是否成功或不。

ORM 自动逃脱防止 SQL 注入,所以我们只需要将请求传递到 save() 方法的输入。

Additional validation happens automatically on fields that are defined as not null (required). If we don’t enter any of the required fields in the sign-up form our screen will look like this:

List of users

Now let’s see how to obtain and see the users that we have registered in the database.

The first thing that we are going to do in our indexAction of theIndexController is to show the result of the search of all the users, which is done simply in the following way Users::find(). Let’s see how our indexAction would look

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();
    }
}

Now, in our view file views/index/index.phtml we will have access to the users found in the database. These will be available in the variable $users. This variable has the same name as the one we use in $this->view->users.

The view will look like this:

views/index/index.phtml

<?php

echo "<h1>Hello!</h1>";

echo $this->tag->linkTo(["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
}

As you can see our variables $users can be iterated and counted, this we will see in depth later on when viewing the models.

Adding Style

To give a design touch to our first application we will add bootstrap and a small template that will be used in all views.

We will add an index.phtml file in theviews folder, with the following content:

app/views/index.phtml

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Phalcon Tutorial</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <?php echo $this->getContent(); ?>
</div>
</body>
</html>

The most important thing to highlight in our template is the function getContent() which will give us the content generated by the view. Now, our application will be something like this:

结论

As you can see, it’s easy to start building an application using Phalcon. The fact that Phalcon runs from an extension significantly reduces the footprint of projects as well as giving it a considerable performance boost.

If you are ready to learn more check out the Rest Tutorial next.