savannabits/charaza-ui

Savannabit的Admin CRUD生成器的Laravel 7 Scaffold

安装: 169

依赖者: 0

建议者: 0

安全性: 0

星标: 49

关注者: 6

分支: 11

开放性问题: 4

类型:项目


README

正在寻找一个Jetstream Tailwindcss,Inertia和Vue3 CRUD生成器?查看我们的姐妹项目,Jetstream Inertia Generator (Jig)

Charaza UI是一个集成了savannabits/savadmin Admin生成器的Laravel Starter,可以帮助您快速启动并快速开发您的下一个laravel项目。Charaza UI配备了最新的laravel工具,不需要您完成太多样板工作。认证模块已经为您搭建。模板已经为您设置。路由也已经为您设置。您只需要开始编写您模块的代码即可。更好的是:您不需要费太多力气就能生成包括模型、API控制器、Datatable控制器、API和后端路由、编辑和显示视图、删除代码在内的完全可操作的模块。savadmin生成器只需一个命令就可以为您完成所有这些

php artisan sv:generate table_name

Screenshot Screenshot Screenshot

特性

  • 使用savannabits/savadmin进行代码生成
  • Laravel 8 Scaffold
  • Laravel Jetstream 前端
  • Livewire 2 Scaffold
  • Laravel Fortify 用户管理
  • Alpine.js配合Livewire,只需Laravel blade即可为您提供真正的SPA体验!
  • 使用Laravel和Vue.js(使用BootstrapVue)进行后端和API生成
  • 个人资料和更新信息
  • 使用Jetstream和Laravel Sanctum的API密钥
  • 可选数据库缓存
  • 使用Laravel TNTSearch进行模糊搜索

安装

Charaza UI旨在简化您开始新项目时的工作。要启动一个全功能的新项目,只需从charaza创建它,如下所示

composer create-project savannabits/charaza-ui my-project

使用方法

该软件包附带可选的Docker配置。强烈建议使用此配置以最小配置体验全部功能。设置好.env变量后,运行以下命令以构建并启动Docker容器

docker-compose build app
docker-compose up -d

这将启动应用程序服务器,该服务器在您在env中配置的端口下公开。要进入容器的shell,有一个简单的shell脚本可以启用此功能

bash app-exec [yoru command]
bash app-exec bash

然而,如果您不想使用Docker,不要担心!您只需根据需要配置数据库变量,然后继续下一步

接下来,按照正常的laravel设置步骤进行

composer install
yarn install
php artisan key:generate
php artisan migrate
php artisan optimize:clear
yarn back-dev (or back-prod)
yarn css-prod (or css-prod)
yarn dev (or prod or watch)

好了!您的系统现在已经设置好,您准备好创建下一个令人惊叹的应用了!

代码生成器

使用代码生成器生成您的命令很容易

  1. 创建您的迁移文件并相应地编辑它
  2. 运行迁移
  3. 使用生成器生成模型、控制器、路由、菜单、视图和js资源。
  4. 根据需要修改它们(自定义)
  5. 如果您没有运行 yarn back-watch,则运行 yarn back-dev 重新构建资源

示例

让我们从articles表生成一个Articles模块

  1. 创建articles
bash app-exec bash #(If you are using docker)
php artisan make:migration create_articles_table
  1. 根据需要编辑articles迁移
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('description');
            $table->text('body');
            $table->foreignId('author_id')->constrained('users')->restrictOnDelete();
            $table->timestamps();
        });
    }
  1. 运行迁移
bash app-exec 'php artisan migrate' #(For docker users)
php artisan migrate #(Non-docker users)
  1. 使用生成器生成模型、控制器、路由、菜单、视图和资源
bash app-exec bash #Enter the container's bash - for Docker users
php artisan sv:generate articles # The code generator

注意如果您已生成文件但想强制覆盖,请使用 ```--force```

 php artisan sv:generate articles --force

输出: 文章 文章 文章

生成的文件

app/Models/Article.php

<?php

namespace App\Models;
/* Imports */
use DateTimeInterface;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
use Rennokki\QueryCache\Traits\QueryCacheable;

class Article extends Model
{
use Searchable;
        use QueryCacheable;
    public $cacheFor=60*60*24; //cache for 1 day
    protected static $flushCacheOnUpdate=true; //invalidate the cache when the database is changed
protected $fillable = [
        'title',
        'description',
        'body',
        'author_id',
    
    ];
    
protected $searchable = [
            'id',
            'title',
            'description',
            'body',
            'author_id',
    
    ];
    
    
    
    protected $dates = [
            'created_at',
        'updated_at',
    ];

    protected $appends = ["api_route"];

    public function toSearchableArray() {
        return collect($this->only($this->searchable))->merge([
            // Add more keys here
        ])->toArray();
    }
    
    /* ************************ ACCESSOR ************************* */

    public function getApiRouteAttribute() {
        return route("api.articles.index");
    }
    protected function serializeDate(DateTimeInterface $date) {
        return $date->format('Y-m-d H:i:s');
    }

    /* ************************ RELATIONS ************************ */
    /**
    * Many to One Relationship to \App\Models\User::class
    * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
    */
    public function author() {
        return $this->belongsTo(\App\Models\User::class,"author_id","id");
    }
}

app/Http/Controllers/Api/ArticleController.php

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Article\IndexArticle;
use App\Http\Requests\Api\Article\StoreArticle;
use App\Http\Requests\Api\Article\UpdateArticle;
use App\Models\Article;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Savannabits\Savadmin\Helpers\ApiResponse;
use Savannabits\Savadmin\Helpers\SavbitsHelper;
use Yajra\DataTables\Facades\DataTables;

class ArticleController  extends Controller
{
    private $api, $helper;
    public function __construct(ApiResponse $apiResponse, SavbitsHelper $helper)
    {
        $this->api = $apiResponse;
        $this->helper = $helper;
    }

    /**
     * Display a listing of the resource (paginated).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function index(IndexArticle $request)
    {
        $data = $this->helper::listing(Article::class, $request)->customQuery(function ($builder) use($request) {
        /**@var  Article|Builder $builder*/
        // Add custom queries here
        })->process();
        return $this->api->success()->message("List of Articles")->payload($data)->send();
    }

    public function dt(Request $request) {
        return DataTables::of(Article::query())
            ->addColumn("actions",function($model) {
                $actions = '';
                if (\Auth::user()->can('articles.show')) $actions .= '<button class="btn btn-outline-primary btn-square action-button mr-2" title="View Details" data-action="show-article" data-tag="button" data-id="'.$model->id.'"><i class="mdi mdi-eye"></i></button>';
                if (\Auth::user()->can('articles.edit')) $actions .= '<button class="btn btn-outline-warning btn-square action-button mr-2" title="Edit Item" data-action="edit-article" data-tag="button" data-id="'.$model->id.'"><i class="mdi mdi-pencil"></i></button>';
                if (\Auth::user()->can('articles.delete')) $actions .= '<button class="btn btn-outline-danger btn-square action-button mr-2" title="Delete Item" data-action="delete-article" data-tag="button" data-id="'.$model->id.'"><i class="mdi mdi-delete"></i></button>';
                return $actions;
            })
            ->rawColumns(['actions'])
            ->make();
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param StoreArticle $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function store(StoreArticle $request)
    {
        try {
            $array = $request->sanitizedArray();
            $article = new Article($array);
            
            // Save Relationships
            $object = $request->sanitizedObject();
            if (isset($object->author)) {
                $article->author()
                    ->associate($object->author->id);
            }
                        

            $article->saveOrFail();
            return $this->api->success()->message('Article Created')->payload($article)->send();
        } catch (\Throwable $exception) {
            \Log::error($exception);
            return $this->api->failed()->message($exception->getMessage())->payload([])->code(500)->send();
        }
    }

    /**
     * Display the specified resource.
     *
     * @param Request $request
     * @param Article $article
     * @return \Illuminate\Http\JsonResponse
     */
    public function show(Request $request, Article $article)
    {
        try {
            //Fetch relationships
            $article->load([
            'author',
        ]);
            return $this->api->success()->message("Article $article->id")->payload($article)->send();
        } catch (\Throwable $exception) {
            return $this->api->failed()->message($exception->getMessage())->send();
        }
    }

    /**
     * Update the specified resource in storage.
     *
     * @param UpdateArticle $request
     * @param {$modelBaseName} $article
     * @return \Illuminate\Http\JsonResponse
     */
    public function update(UpdateArticle $request, Article $article)
    {
        try {
            $data = $request->sanitizedArray();
            $article->update($data);
            
            // Save Relationships
                $object = $request->sanitizedObject();
            if (isset($object->author)) {
                $article->author()
                    ->associate($object->author->id);
            }
                        

            $article->saveOrFail();
            return $this->api->success()->message("Article has been updated")->payload($article)->code(200)->send();
        } catch (\Throwable $exception) {
            \Log::error($exception);
            return $this->api->failed()->code(400)->message($exception->getMessage())->send();
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param Article $article
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function destroy(Article $article)
    {
        $article->delete();
        return $this->api->success()->message("Article has been deleted")->payload($article)->code(200)->send();
    }

}

附加路由: api.php

    /* Auto-generated articles api routes */
    Route::group(['prefix' => $apiPrefix,'as' => 'api.', 'namespace' => $apiNamespace], function() {
        Route::group(['middleware' => ["auth:sanctum","verified"]], function() {
            Route::group(['prefix' => "articles", 'as' => 'articles.'],function() {
                Route::get("dt", "ArticleController@dt")->name('dt');
            });
            Route::apiResource('articles',"ArticleController")->parameters(["articles" => "article"]);
        });
    });

web.php

    /* Auto-generated admin routes */
    
    Route::group(["prefix" => config('savadmin.app.prefix',''),
        "namespace" => "Admin",
        "as" => config('savadmin.app.prefix').".",'middleware' => ['auth','verified']],function() {
        Route::group(['as' => "articles.", 'prefix' => "articles"], function() {
            Route::get('','ArticleController@index')->name('index');
        });
    });

您可以通过以下方式检查其余的文件

  • app/Http/Controllers/Admin/ArticleController.php
  • resources/js/backend/articles.js
  • resources/views/backend/articles/*

贡献

感谢您考虑为CharazaUI做出贡献!请通过savannabits@gmail.com联系Savannabits获取更多信息。

行为准则

为了确保Charaza社区对所有成员都友好,请阅读并遵守行为准则

安全漏洞

如果您在Charaza中发现安全漏洞,请通过maosa.sam@gmail.com给Sam Maosa发送电子邮件。所有安全漏洞都将得到及时处理。

许可证

Charaza UI Starter是开源软件,许可协议为MIT许可证