ホームページ > バックエンド開発 > PHPチュートリアル > Flight を使用したシンプルなブログの構築 - パート 1

Flight を使用したシンプルなブログの構築 - パート 1

PHPz
リリース: 2024-07-18 01:21:41
オリジナル
1189 人が閲覧しました

皆さんこんにちは! PHP 用の Flight Framework に追加された新機能のいくつかを紹介する時期が来たと考えました。今年の初めに、Flight のオリジナルの作成者である Mike Cao は、mikecao/flight の所有権を新しい Flight PHP 組織に譲渡することを親切にも申し出てくれました。移行されてから、ミドルウェア、ルート グループ化、DIC、その他の機能などの機能が追加されました。この投稿は少し長くなりますが、ブログの構築方法について適切なコンテキストを理解できるように、多くのコード例を含めているだけです。

まず、これを邪魔にならないようにしましょう。 Flight は、いくつかの付加機能を備えたシンプルなフレームワークであることを目的としています。 Laravel や Symfony や Yii や Cake や [空白を埋める] とは競合しません。このフレームワークは、単純から中規模のプロジェクト向けに構築されています。また、理解したり訓練したりするのが難しいコード内の「魔法」を好まない人にも対応します。これは、多くのランダムな include ステートメントを含む生の 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 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>
ログイン後にコピー

アクティブレコードデータベースクラス

Flight には、Flight Active Record と呼ばれるデータベースと対話するためのプラグインがあります。このプラグインを使用すると、アプリ内で生の SQL をあまり書かずに済むようになります (ただし、アクティブなレコード/ORM/マッパーに強制的に実行させるよりも、生の SQL クエリを書いた方が効率的な場合もあります)。基本的に、アクティブ レコード拡張機能は、データベース内のテーブル内の行を操作するのに役立ちます。データベース内の 1 つの行を 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 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート