Xây dựng CLI Dashboard tương tác với Laravel Prompts

· 4 min read

Quản lý blog dựa trên file bao gồm việc tạo file, định dạng ngày tháng, và quản lý frontmatter. Mặc dù tôi có thể làm điều này thủ công trong VS Code, việc có một công cụ CLI khiến nó cảm giác như một CMS thực sự.

Laravel gần đây đã giới thiệu Laravel Prompts, một package giúp xây dựng form CLI đẹp và dễ dàng. Hãy cùng xây dựng lệnh php artisan blog:manage.

Thiết lập ban đầu

Chúng ta muốn một lệnh cho phép:

  1. Tạo bài viết mới.
  2. Liệt kê các bản draft gần đây.
  3. Publish một bản draft.

Tạo Command

Đầu tiên, tạo command:

php artisan make:command ManageBlog

Triển khai

Chúng ta sẽ sử dụng select, text, confirm, và multiselect từ namespace Laravel\Prompts.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Carbon\Carbon;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\multiselect;
use function Laravel\Prompts\info;

class ManageBlog extends Command
{
    protected $signature = 'blog:manage';
    protected $description = 'Interactive blog management dashboard';

    public function handle()
    {
        $action = select(
            label: 'What would you like to do?',
            options: [
                'create' => 'Create a new post',
                'view' => 'View drafts',
                'exit' => 'Exit',
            ]
        );

        match ($action) {
            'create' => $this->createPost(),
            'view' => $this->viewDrafts(),
            'exit' => $this->info('Goodbye!'),
        };
    }

    protected function createPost()
    {
        $title = text('Post Title', required: true, placeholder: 'My Awesome Post');
        
        $slug = text(
            label: 'Slug',
            default: Str::slug($title),
            validate: fn (string $value) => match (true) {
                strlen($value) < 3 => 'The slug must be at least 3 characters.',
                default => null
            }
        );

        $tags = multiselect(
            label: 'Select Tags',
            options: ['laravel', 'php', 'javascript', 'css', 'devops', 'testing'],
            scroll: 5
        );

        $isDraft = confirm('Save as draft?', default: false);

        $date = Carbon::now()->format('Y-m-d');
        $filename = "{$date}-{$slug}.md";
        $path = base_path("content/posts/" . Carbon::now()->format('Y'));

        // Ensure directory exists
        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }

        $content = <<<EOT
---
title: "{$title}"
date: {$date}
description: ""
tags: {$this->formatTags($tags)}
draft: {$this->boolToString($isDraft)}
---

Write your content here...
EOT;

        file_put_contents("$path/$filename", $content);

        info("Post created at: $path/$filename");
    }

    protected function formatTags(array $tags): string
    {
        return '["' . implode('", "', $tags) . '"]';
    }

    protected function boolToString(bool $val): string
    {
        return $val ? 'true' : 'false';
    }
    
    protected function viewDrafts()
    {
        // Implementation for scanning standard directory for `draft: true`
        info("Feature coming soon...");
    }
}

Tại sao chọn Laravel Prompts?

1. Validation

Validation diễn ra inline. Bạn không cần submit form để thấy mình đã mắc lỗi.

2. Select có thể tìm kiếm

Nếu bạn có 50 tag, multiselect cho phép bạn gõ để lọc chúng. Đây là cải tiến UI lớn so với input CLI tiêu chuẩn.

3. Tính nhất quán

Giao diện khớp với installer của Laravel và các công cụ ecosystem khác, khiến các công cụ nội bộ tùy chỉnh của bạn cảm giác "chính thức".

Các bước tiếp theo

Bạn có thể mở rộng điều này để:

  • Chạy grammar checker trên nội dung file.
  • Tự động mở file mới trong VS Code sử dụng exec("code $path").
  • Tạo AI summary sử dụng LLM API cho trường description.

Công cụ CLI không nhất thiết phải là các argument xấu xí. Với Prompts, chúng có thể trở nên thú vị khi sử dụng.

Bình luận