首页 > 后端开发 > php教程 > 使用 Flight 构建简单的博客 - 第 1 部分

使用 Flight 构建简单的博客 - 第 1 部分

PHPz
发布: 2024-07-18 01:21:41
原创
1188 人浏览过

大家好!我认为是时候展示 PHP 飞行框架中添加的一些新功能了。今年早些时候,Flight Mike Cao 的原始创建者慷慨地提出将 mikecao/flight 的所有权转让给一个新的 Flight PHP 组织。自从它被移动以来,我们添加了中间件、路由分组、DIC 和其他功能等功能。这篇文章会有点长,但这只是因为我包含了很多代码示例,因此您可以了解如何构建博客的正确上下文。

首先,让我们解决这个问题。 Flight 是一个带有一些花哨功能的简单框架。它不会与 Laravel 或 Symfony 或 Yii 或 Cake 或 [填空] 竞争。该框架实际上是针对简单到中型项目而构建的。它还迎合了那些不喜欢代码中难以理解或难以训练的“魔法”的人。它更适合那些刚刚开始涉足框架的开发人员,而不是带有大量随机包含语句的原始 PHP。

太长了;博士

很多很酷的功能,很好的简单实现,等等等等,这是代码。请前往第 2 部分了解精彩内容!

安装

让我们使用 Composer 来开始这个聚会。

composer create-project flightphp/skeleton blog/
cd blog/
登录后复制

配置您的新项目

要做的第一件事是转到 app/config/config.php 文件,我们可以在其中放置任何配置,例如 API 密钥、数据库凭据和应用程序的其他重要凭据。对于本博客,我们将取消 SQLite 数据库路径的 file_path 行的注释:

return [
    'database' => [
        // 'host' => 'localhost',
        // 'dbname' => 'dbname',
        // 'user' => 'user',
        // 'password' => 'password'
        'file_path' => __DIR__ . $ds . '..' . $ds . 'database.sqlite'
    ],
];
登录后复制

创建博客数据库

Flight 现在附带一个名为 runway 的命令行实用程序。这允许您为 Flight 插件甚至您自己的项目创建自定义命令。

作为骨架的一部分,它附带了一个 SampleDatabaseCommand,它将为我们正在创建的这个博客项目提供一个起点。

运行以下命令,它应该会为您填充您的数据库!

php runway init:sample-db
登录后复制

接下来我们将打开 app/config/services.php 文件并取消注释 SQLite 行。

// see how the $config variable references the config line we uncommented earlier?
$dsn = 'sqlite:' . $config['database']['file_path'];
登录后复制

为了确保我们已正确设置所有内容,请运行composer start,然后在浏览器中访问http://localhost:8000/。您应该看到以下屏幕:

Default Home Page

您还会注意到角落里有一个方便的调试工具栏,其中包含一些自定义的 Flight 面板,可帮助您了解应用程序中发生的情况。如果您将鼠标悬停在工具栏中的各个项目上,您将看到各种悬停,您可以单击这些悬停以保持页面上的粘性(稍后会详细介绍)。

Flight Tracy Extensions

构建 HTML 模板

Flight 框架中确实附带了一个非常基本的 HTML 模板解决方案。这对于非常简单的网站或者只是返回一段简单的 HTML 来说就很好了。建议使用其他模板平台,例如 Latte、Twig 或 Blade。在本教程中,我们将使用 Latte,因为它很棒并且没有依赖项(您会注意到在 Flight 中我们不喜欢不必要的依赖项)!

继续安装 Latte

composer require latte/latte
登录后复制

将其添加到您的 services.php

$Latte = new \Latte\Engine;
$Latte->setTempDirectory(__DIR__ . '/../cache/');

// This is fun feature of Flight. You can remap some built in functions with the framework
// to your liking. In this case, we're remapping the Flight::render() method.
$app->map('render', function(string $templatePath, array $data = [], ?string $block = null) use ($app, $Latte) {
    $templatePath = __DIR__ . '/../views/'. $templatePath;
    $Latte->render($templatePath, $data, $block);
});
登录后复制

现在我们已经有了模板引擎,我们可以创建一个基本 HTML 文件。让我们创建一个layout.latte 文件:

<!doctype html>
<html lang="en">
    <head>
        <!-- Picnic.css is a CSS framework that works out of the box with little configuration -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/picnic">
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>{$page_title ? $page_title.' - '}Blog Built with Flight!</title>
    </head>
    <body style="padding: 15px;">
        {block content}{/block}
    </body>
</html>
登录后复制

Active Record 数据库类

Flight 有一个用于与名为 Flight Active Record 的数据库进行交互的插件。该插件可以帮助您不必在应用程序中编写太多原始 SQL(尽管有时编写原始 SQL 查询比强制活动记录/ORM/映射器为您运行它更有效)。基本上,活动记录扩展可以帮助您与数据库中表中的行进行交互:数据库中的一行可以映射到 PHP 中的一个对象(自动完成列),从而节省时间和理智。让我们将其安装到我们的项目中。

composer require flightphp/active-record
登录后复制

现在您可以使用 runway 自动为您创建活动记录类,并且它将自动创建您的属性作为注释(用于自动完成)!

首先让我们创建 posts 类。第一次运行此程序时,需要设置数据库连接。

$ php runway make:record posts
Database configuration not found. Please provide the following details:
Driver (mysql/pgsql/sqlite): sqlite
Database file path [database.sqlite]: app/database.sqlite
Username (for no username, press enter) []: 
Password (for no password, press enter) []: 
Writing database configuration to .runway-config.json
Creating directory app/records
Active Record successfully created at app/records/PostRecord.php
登录后复制

现在我们将创建评论记录类:

$ php runway make:record comments
登录后复制

It's Time for your First Page!

Flight uses the MVC pattern. In order to create a new page you need to define a route in your routes.php file, create a new method in a controller, and then create the HTML file that the browser will serve. You can use runway to help you get started with a new controller class:

php runway make:controller Home
登录后复制

And you should see something similar to the following:

$ php runway make:controller Home
Controller successfully created at app/controllers/HomeController.php
登录后复制

If you go to app/controllers/HomeController.php go ahead and add this new method to your HomeController:

/**
 * Index
 * 
 * @return void
 */
public function index(): void
{
    $this->app->render('home.latte', [ 'page_title' => 'Home' ]);
}
登录后复制

And create a new file in app/views/home.latte and put in this code:

{extends 'layout.latte'}

{block content}
<h1>My Home Page</h1>
<p><a href="/blog">View My Blog!</a></p>
{/block}
登录后复制

Finally let's change up the routes to the routes.php file. Go ahead and remove any code in the routes file that begins with $router-> and add a new route for your home router:

$router->get('/', \app\controllers\HomeController::class . '->index');
登录后复制

Make sure you run composer start so that your development server is up. If you go to http://localhost:8000/ in your browser, you should see something like this!

Flight Demo Home Page

Now we're cookin'!

Adding Routes for the Blog

Let's go ahead and add all the methods in your controller, routes, and html files. Let's start with adding the routes in your routes.php file:

// Blog
$router->group('/blog', function(Router $router) {

    // Posts
    $router->get('', \app\controllers\PostController::class . '->index');
    $router->get('/create', \app\controllers\PostController::class . '->create');
    $router->post('', \app\controllers\PostController::class . '->store');
    $router->get('/@id', \app\controllers\PostController::class . '->show');
    $router->get('/@id/edit', \app\controllers\PostController::class . '->edit');
    $router->post('/@id/edit', \app\controllers\PostController::class . '->update');
    $router->get('/@id/delete', \app\controllers\PostController::class . '->destroy');
});
登录后复制

So you'll notice we use a group() method here to group all the routes together that start with /blog. We could actually rewrite the routes like the following with the group() method and the same thing would happen:

// Posts
$router->get('/blog', \app\controllers\PostController::class . '->index');
$router->get('/blog/create', \app\controllers\PostController::class . '->create');
登录后复制

With the controller, first let's create an empty controller with runway:

php runway make:controller Post
登录后复制

You can copy the code below for your PostController.php:

<?php

declare(strict_types=1);

namespace app\controllers;

use app\records\CommentRecord;
use app\records\PostRecord;
use flight\Engine;

class PostController
{
    /** @var Engine */
    protected Engine $app;

    /**
     * Constructor
     */
    public function __construct(Engine $app)
    {
        $this->app = $app;
    }

    /**
     * Index
     *
     * @return void
     */
    public function index(): void
    {
        $PostRecord = new PostRecord($this->app->db());
        $posts = $PostRecord->order('id DESC')->findAll();
        $CommentRecord = new CommentRecord($this->app->db());
        foreach($posts as &$post) {
            $post->comments = $CommentRecord->eq('post_id', $post->id)->findAll();
        }
        $this->app->render('posts/index.latte', [ 'page_title' => 'Blog', 'posts' => $posts]);
    }

    /**
     * Create
     *
     * @return void
     */
    public function create(): void
    {
        $this->app->render('posts/create.latte', [ 'page_title' => 'Create Post']);
    }

    /**
     * Store
     *
     * @return void
     */
    public function store(): void
    {
        $postData = $this->app->request()->data;
        $PostRecord = new PostRecord($this->app->db());
        $PostRecord->title = $postData->title;
        $PostRecord->content = $postData->content;
        $PostRecord->username = $postData->username;
        $PostRecord->created_at = gmdate('Y-m-d H:i:s');
        $PostRecord->updated_at = null;
        $PostRecord->save();
        $this->app->redirect('/blog');
    }

    /**
     * Show
     *
     * @param int $id The ID of the post
     * @return void
     */
    public function show(int $id): void
    {
        $PostRecord = new PostRecord($this->app->db());
        $post = $PostRecord->find($id);
        $CommentRecord = new CommentRecord($this->app->db());
        $post->comments = $CommentRecord->eq('post_id', $post->id)->findAll();
        $this->app->render('posts/show.latte', [ 'page_title' => $post->title, 'post' => $post]);
    }

    /**
     * Edit
     *
     * @param int $id The ID of the post
     * @return void
     */
    public function edit(int $id): void
    {
        $PostRecord = new PostRecord($this->app->db());
        $post = $PostRecord->find($id);
        $this->app->render('posts/edit.latte', [ 'page_title' => 'Update Post', 'post' => $post]);
    }

    /**
     * Update
     *
     * @param int $id The ID of the post
     * @return void
     */
    public function update(int $id): void
    {
        $postData = $this->app->request()->data;
        $PostRecord = new PostRecord($this->app->db());
        $PostRecord->find($id);
        $PostRecord->title = $postData->title;
        $PostRecord->content = $postData->content;
        $PostRecord->username = $postData->username;
        $PostRecord->updated_at = gmdate('Y-m-d H:i:s');
        $PostRecord->save();
        $this->app->redirect('/blog');
    }

    /**
     * Destroy
     *
     * @param int $id The ID of the post
     * @return void
     */
    public function destroy(int $id): void
    {
        $PostRecord = new PostRecord($this->app->db());
        $post = $PostRecord->find($id);
        $post->delete();
        $this->app->redirect('/blog');
    }
}
登录后复制

Let's kill some time and talk about a few things that are going on in the controller.

First off we are now using our new active record classes:

$PostRecord = new PostRecord($this->app->db());
$posts = $PostRecord->order('id DESC')->findAll();
登录后复制

We are injecting the database we setup in the services.php file above with $this->app->db();. Technically we could also just use Flight::db() as this points to the global $app variable.

Active Record classes are really helpful to simplify interactions with a database. We could rewrite the above in the following code:

$posts = $this->app->db()->fetchAll("SELECT * FROM posts ORDER BY id DESC");
登录后复制

This might not be the best example of how helpful an active record could be. But in part 2 I'll show you some hidden gems inside these classes that make it so much better than writing raw SQL.

Now let's talk HTML files. Here are the files we'll need for the post routes:

app/views/posts/index.latte

{extends '../layout.latte'}

{block content}

<h1>My Amazing Blog</h1>
<p>Welcome to my blog!</p>
<p><a class="button" href="/blog/create">Create a new post</a></p>
{foreach $posts as $post}
    {first}
    <h2>Recent Posts</h2>
    {/first}
    <hr>
    <h3><a href="/blog/{$post->id}">{$post->title}</a></h3>
    <p><small>By: {$post->username} on {$post->created_at|date:'d.m.Y G:i a'}</small></p>
    <p>Comments: {count($post->comments)}
    <p>{$post->content|truncate:100}</p>
    <hr>
    <a class="pseudo button" href="/blog/{$post->id}/edit">Update</a> - <a class="pseudo button" href="/blog/{$post->id}/delete">Delete</a>
{/foreach}

{/block}
登录后复制

app/views/posts/show.latte

{extends '../layout.latte'}

{block content}
<a href="/blog">&lt; Back to blog</a>
<h1>{$post->title}</h1>
<p>Created by: {$post->username} on {$post->created_at|date:'d.m.Y G:i a'}.</p>
<div>
    {$post->content|breakLines}
</div>
<p n:if="$post->update_at">Last update: {$post->update_at|date:'d.m.Y G:i a'}.</p>

<h2>Comments</h2>
{foreach $post->comments as $comment}
<div>
    <p>{$comment->username} on {$comment->created_at|date:'d.m.Y G:i a'}.</p>
    <div>
        {$comment->content|breakLines}
    </div>
    <hr>
    <a class="pseudo button" href="/blog/{$post->id}/comment/{$comment->id}/delete">Delete</a>
</div>
{else}
<p>No comments yet.</p>
{/foreach}

<h2>Add comment</h2>
<form action="/blog/{$post->id}/comment" method="post">
    <div>
        <label for="username">Username:</label>
        <input name="username" id="username" placeholder="Username" required />
    </div>
    <div>
        <label for="content">Comment:</label>
        <textarea name="content" id="content" placeholder="Comment" required></textarea>
    </div>
    <div>
        <button type="submit">Add Comment</button>
    </div>
</form>
{/block}
登录后复制

app/views/posts/create.latte

{extends '../layout.latte'}

{block content}
<h1>Create a Post</h1>
<form action="/blog" method="post">
    <label><input type="text" name="title" placeholder="Title" required></label>
    <label><textarea name="content" placeholder="Content" required></textarea></label>
    <label><input type="text" name="username" placeholder="Username" required></label>

    <button type="submit">Create</button>
</form>
{/block}
登录后复制

app/views/posts/edit.latte

{extends '../layout.latte'}

{block content}
<h1>Update a Post</h1>
<form action="/blog/{$post->id}/edit" method="post">
    <label for="title">Title</label>
    <input type="text" name="title" placeholder="Title" value="{$post->title}" required>

    <label for="content">Content</label>
    <label><textarea name="content" placeholder="Content" required>{$post->content}</textarea>

    <label for="username">Username</label>
    <label><input type="text" name="username" placeholder="Username" value="{$post->username}" required>

    <button type="submit">Update</button>
</form>
{/block}
登录后复制

Create a new post

Now that we've got all the pieces in place, you should be able to load up your blog page, create a new post, see a post, and delete a post. You may have noticed we've included a comment form but the form doesn't actually work. We can fix that real quick! Let's create a controller with runway:

php runway make:controller Comment
登录后复制

Now you can make the CommentController.php look like the following:

<?php

declare(strict_types=1);

namespace app\controllers;

use app\records\CommentRecord;
use flight\Engine;

class CommentController
{
    /** @var Engine */
    protected Engine $app;

    /**
     * Constructor
     */
    public function __construct(Engine $app)
    {
        $this->app = $app;
    }

    /**
     * Store
     * 
     * @param int $id The post ID
     * 
     * @return void
     */
    public function store(int $id): void
    {
        $postData = $this->app->request()->data;
        $CommentRecord = new CommentRecord($this->app->db());
        $CommentRecord->post_id = $id;
        $CommentRecord->username = $postData->username;
        $CommentRecord->content = $postData->content;
        $CommentRecord->created_at = gmdate('Y-m-d H:i:s');
        $CommentRecord->updated_at = null;
        $CommentRecord->save();
        $this->app->redirect('/blog/' . $id);
    }

    /**
     * Destroy
     * 
     * @param int $id The post ID
     * @param int $comment_id The comment ID
     * 
     * @return void
     */
    public function destroy(int $id, int $comment_id): void
    {
        $CommentRecord = new CommentRecord($this->app->db());
        $CommentRecord->find($comment_id);
        $CommentRecord->delete();
        $this->app->redirect('/blog/' . $id);
    }

}
登录后复制

Now let's add a couple other routes in the group chunk of code in routes.php

// Blog
$router->group('/blog', function(Router $router) {

    // Posts

    // post routes...

    // Comments
    $router->post('/@id/comment', \app\controllers\CommentController::class . '->store');
    $router->get('/@id/comment/@comment_id/delete', \app\controllers\CommentController::class . '->destroy');
});
登录后复制

Conclusion (sort of)

With these two additions to the code, you have a fully functioning blog built with Flight! This got the job done and you now have a blog, but the code is somewhat clunky and could be improved to have some pretty nifty features like middleware, permissions, and writing less code! Hop over to part 2

Go ahead and leave any questions in comments below or join us in the chatroom!

If you want to see the final product with all the improvements here's the code!

以上是使用 Flight 构建简单的博客 - 第 1 部分的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板