”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 Flight 构建简单的博客 - 第 1 部分

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

发布于2024-08-01
浏览:351

Hey everyone! I figured it was time to showcase some of the new features that have been added to the Flight Framework for PHP. Earlier this year the original creator of Flight Mike Cao graciously offered to transfer ownership of mikecao/flight over to a new Flight PHP organization. Since it's been moved we've added features like middleware, route grouping, DIC, and other features. This post will be a little longer, but it's just because I've included a lot of code examples so you can have the right context into how your blog will get built.

First off, let's just get this out of the way. Flight is meant to be a simple framework with a few bells and whistles. It will not compete with Laravel or Symfony or Yii or Cake or [fill in the blank]. This framework is really built towards simple to medium size projects. It also caters to those who don't like "magic" in their code that's hard to understand or train to. It's geared more towards developers who are just starting to branch into frameworks instead of raw PHP with a lot of random include statements.

tl;dr

Lots of cool features, nice simple implementation, blah blah blah here's the code. Go to part 2 for the cool stuff!

Installation

Let's use Composer to get this party started.

composer create-project flightphp/skeleton blog/
cd blog/

Configure your New Project

First thing to do is to go to the app/config/config.php file where we can put any config like API keys, database credentials, and other important credentials for our app. For this blog, we'll uncomment the line with file_path for our SQLite database path:

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

Create the Blog Database

Flight now comes with a command line utility called runway. This allows you to create custom commands for a plugin for Flight, or even for your own project.

As part of the skeleton, it comes with a SampleDatabaseCommand that will give us a starting point with this blog project we are creating.

Run the below command and it should populate your database for you!

php runway init:sample-db

Next we'll open up the app/config/services.php file and uncomment the line for SQLite.

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

Just to make sure we've got everything setup correctly, run composer start and then go to http://localhost:8000/ in your browser. You should see the following screen:

Default Home Page

You'll also notice in the corner you have a handy debug toolbar with some custom Flight panels to help you understand what's going on in your application. If you hover over the various items in the toolbar, you'll see a variety of hovers that you can click on to keep sticky on the page (more on that later).

Flight Tracy Extensions

Building the HTML Templates

Flight does come with a very basic HTML templating solution already in the framework. This is just fine for very simple sites or just to return a simple piece of HTML. It is recommended to use another templating platform such as Latte, Twig, or Blade. In this tutorial, we're going to use Latte because it is awesome and has no dependencies (you'll notice in Flight we do not like unnecessary dependencies)!

Go ahead and install Latte

composer require latte/latte

Add this to your 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);
});

Now that we have a templating engine in place, we can create a base HTML file. Let's create a layout.latte file:


    
        
        
        
        
        {$page_title ? $page_title.' - '}Blog Built with Flight!
    
    
        {block content}{/block}
    

Active Record Database Class

Flight has a plugin for interacting with a database called Flight Active Record. This plugin helps you not write as much raw SQL in your apps (although sometimes it is more efficient to write a raw SQL query instead of forcing an active record/ORM/mapper to run it for you). Basically the active record extension helps you interact with rows within tables in your database: one row in a database can be mapped to an object in PHP (with autocomplete for the columns) saving time and sanity. Let's get it installed in our project.

composer require flightphp/active-record

Now you can use runway to create your active record classes automatically for you and it will create your properties as comments automatically (for autocomplete)!

First let's create the posts class. The first time you run this, it needs to setup the connection for the database.

$ 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

Now we'll create the comments record class:

$ 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}

My Home Page

View My Blog!

{/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:

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}

My Amazing Blog

Welcome to my blog!

Create a new post

{foreach $posts as $post} {first}

Recent Posts

{/first}

{$post->title}

By: {$post->username} on {$post->created_at|date:'d.m.Y G:i a'}

Comments: {count($post->comments)}

{$post->content|truncate:100}


Update - Delete {/foreach} {/block}

app/views/posts/show.latte

{extends '../layout.latte'}

{block content}
< Back to blog

{$post->title}

Created by: {$post->username} on {$post->created_at|date:'d.m.Y G:i a'}.

{$post->content|breakLines}

Last update: {$post->update_at|date:'d.m.Y G:i a'}.

Comments

{foreach $post->comments as $comment}

{$comment->username} on {$comment->created_at|date:'d.m.Y G:i a'}.

{$comment->content|breakLines}

Delete
{else}

No comments yet.

{/foreach}

Add comment

{/block}

app/views/posts/create.latte

{extends '../layout.latte'}

{block content}

Create a Post

{/block}

app/views/posts/edit.latte

{extends '../layout.latte'}

{block content}

Update a Post

{/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:

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!

版本声明 本文转载于:https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-1-4ap8?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 在细胞编辑后,如何维护自定义的JTable细胞渲染?
    在细胞编辑后,如何维护自定义的JTable细胞渲染?
    在JTable中维护jtable单元格渲染后,在JTable中,在JTable中实现自定义单元格渲染和编辑功能可以增强用户体验。但是,至关重要的是要确保即使在编辑操作后也保留所需的格式。在设置用于格式化“价格”列的“价格”列,用户遇到的数字格式丢失的“价格”列的“价格”之后,问题在设置自定义单元格...
    编程 发布于2025-04-02
  • 如何将来自三个MySQL表的数据组合到新表中?
    如何将来自三个MySQL表的数据组合到新表中?
    mysql:从三个表和列的新表创建新表 答案:为了实现这一目标,您可以利用一个3-way Join。 选择p。*,d.content作为年龄 来自人为p的人 加入d.person_id = p.id上的d的详细信息 加入T.Id = d.detail_id的分类法 其中t.taxonomy =...
    编程 发布于2025-04-02
  • 如何在Java中正确显示“ DD/MM/YYYY HH:MM:SS.SS”格式的当前日期和时间?
    如何在Java中正确显示“ DD/MM/YYYY HH:MM:SS.SS”格式的当前日期和时间?
    如何在“ dd/mm/yyyy hh:mm:mm:ss.ss”格式“ gormat 解决方案:的,请访问量很大,并应为procectiquiestate的,并在整个代码上正确格式不多: java.text.simpledateformat; 导入java.util.calendar; 导入java...
    编程 发布于2025-04-02
  • 如何同步迭代并从PHP中的两个等级阵列打印值?
    如何同步迭代并从PHP中的两个等级阵列打印值?
    同步的迭代和打印值来自相同大小的两个数组使用两个数组相等大小的selectbox时,一个包含country代码的数组,另一个包含乡村代码,另一个包含其相应名称的数组,可能会因不当提供了exply for for for the uncore for the forsion for for ytry...
    编程 发布于2025-04-02
  • 如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    在Visual Studio 2012 尽管已安装了MySQL Connector v.6.5.4,但无法将MySQL数据库添加到实体框架的“ DataSource对话框”中。为了解决这一问题,至关重要的是要了解MySQL连接器v.6.5.5及以后的6.6.x版本将提供MySQL的官方Visual...
    编程 发布于2025-04-02
  • 对象拟合:IE和Edge中的封面失败,如何修复?
    对象拟合:IE和Edge中的封面失败,如何修复?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    编程 发布于2025-04-02
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-04-02
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中,使用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-04-02
  • 如何干净地删除匿名JavaScript事件处理程序?
    如何干净地删除匿名JavaScript事件处理程序?
    删除匿名事件侦听器将匿名事件侦听器添加到元素中会提供灵活性和简单性,但是当要删除它们时,可以构成挑战,而无需替换元素本身就可以替换一个问题。 element? element.addeventlistener(event,function(){/在这里工作/},false); 要解决此问题,请考虑...
    编程 发布于2025-04-02
  • 如何在Java的全屏独家模式下处理用户输入?
    如何在Java的全屏独家模式下处理用户输入?
    Handling User Input in Full Screen Exclusive Mode in JavaIntroductionWhen running a Java application in full screen exclusive mode, the usual event ha...
    编程 发布于2025-04-02
  • 如何将多种用户类型(学生,老师和管理员)重定向到Firebase应用中的各自活动?
    如何将多种用户类型(学生,老师和管理员)重定向到Firebase应用中的各自活动?
    Red: How to Redirect Multiple User Types to Respective ActivitiesUnderstanding the ProblemIn a Firebase-based voting app with three distinct user type...
    编程 发布于2025-04-02
  • 如何在鼠标单击时编程选择DIV中的所有文本?
    如何在鼠标单击时编程选择DIV中的所有文本?
    在鼠标上选择div文本单击带有文本内容,用户如何使用单个鼠标单击单击div中的整个文本?这允许用户轻松拖放所选的文本或直接复制它。 在单个鼠标上单击的div元素中选择文本,您可以使用以下Javascript函数: function selecttext(canduterid){ if(do...
    编程 发布于2025-04-02
  • 如何使用Python理解有效地创建字典?
    如何使用Python理解有效地创建字典?
    在python中,词典综合提供了一种生成新词典的简洁方法。尽管它们与列表综合相似,但存在一些显着差异。与问题所暗示的不同,您无法为钥匙创建字典理解。您必须明确指定键和值。 For example:d = {n: n**2 for n in range(5)}This creates a dicti...
    编程 发布于2025-04-02
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-04-02
  • 如何正确使用与PDO参数的查询一样?
    如何正确使用与PDO参数的查询一样?
    在pdo 中使用类似QUERIES在PDO中的Queries时,您可能会遇到类似疑问中描述的问题:此查询也可能不会返回结果,即使$ var1和$ var2包含有效的搜索词。错误在于不正确包含%符号。通过将变量包含在$ params数组中的%符号中,您确保将%字符正确替换到查询中。没有此修改,PDO...
    编程 发布于2025-04-02

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3