oza75/laravel-hubble

立即创建一个漂亮的laravel仪表盘

v0.1.8 2021-05-16 20:48 UTC

This package is auto-updated.

Last update: 2024-09-26 02:05:58 UTC


README

Latest Version on Packagist Build Status Quality Score Total Downloads

立即使用laravel构建一个漂亮的仪表盘。

Details screen

要求

  • php : ^7.1
  • Laravel : ^6.0

安装

您可以通过composer安装此包

composer require oza75/laravel-hubble

然后安装laravel-hubble

php artisan hubble:install

# Now Add App\Providers\HubbleServiceProvider into providers array in your config/app.php

现在转到: http://yourapp.tld/hubble (如果您使用 artisan serve,则为 https://:8000/hubble

身份验证

Hubble 使用默认的 Laravel 授权网关来检查用户是否有权访问仪表盘。默认情况下,所有人都可以访问 Hubble 仪表盘。您可以使用 App\Providers\HubbleServiceProvider 中的 authorizesAccess 方法来限制访问。

   // file: app/Providers/HubbleServiceProvider.php

   /**
    * Determines if a given user can access to hubble dashboard.
    * By default every user can access to hubble
    *
    * @param User $user
    * @return bool
    */
    public function authorizesAccess(User $user): bool
    {
        return $user->isAdmin();
    }

使用方法

资源

Hubble 资源是一个简单的 PHP 类,旨在表示您想要添加的资源,即它具有的不同字段、操作、过滤器等。

创建资源

您可以通过运行 hubble:resource 命令来创建一个新的资源

php artisan hubble:resource UserResource

这将在 app/Hubble 文件夹下自动创建一个新的资源

<?php

namespace App\Hubble;

use Illuminate\Database\Eloquent\Builder;
use Oza75\LaravelHubble\Action;
use Oza75\LaravelHubble\Field;
use Oza75\LaravelHubble\Filter;
use Oza75\LaravelHubble\Actions\DeleteAction;

use App\Hubble\Resource;

class UserResource extends Resource
{

    /**
     * @var string The title will be used as your resource name in the ui
     */
    protected $title = "Users";

    /**
     * @var string[]
     */
    protected $searchColumns = ['id'];

    /**
     * @var string used to show resource value in relationship
     */
    protected $displayColumn = 'id';

    /**
     * Get the fields displayed that the user resource
     *
     * @return Field[] array of fields
     */
    public function fields()
    {
        return [
            Field::make('id', 'ID'),
            Field::make('name', 'Name')
        ];
    }

    /**
     * Register all actions that the user resource have
     *
     * @return Action[] array of actions
     */
    public function actions()
    {
        return [
            DeleteAction::make(),

        ];
    }

    /**
     * Register all filters that the user resource have
     *
     * @return Filter[] array of filters
     */
    public function filters()
    {
        return [];
    }

    /**
     * @return Builder
     */
    public function baseQuery(): Builder
    {
        return \App\User::query();
    }

    /**
     * Return this resource icon
     *
     * @return string|null
     */
    public function icon()
    {
        return null;
    }
}

在您的资源生成后,您需要设置 Hubble 应该使用的 eloquent builder 来获取您的数据。在生成此资源时,我们将尝试根据通过 php artisan hubble:resource 命令传入的资源名称获取 eloquent builder。您可以修改此查询构建器以添加一些计算字段。

    /**
     * @return Builder
     */
    public function baseQuery(): Builder
    {
        return \App\User::query()->select('*')->selectRaw('age > 18 as is_adult');
    }

fields 方法用于返回您想要显示的所有字段。默认情况下,Hubble 带有一些字段,如 TextFieldTextareaFieldImageField 等。但您也可以创建自己的自定义字段。

    /**
     * Get the fields displayed that the user resource
     *
     * @return Field[] array of fields
     */
    public function fields()
    {
        return [
            Field::make('id', 'ID'),

            TextField::make('name', 'Name')->sortable(),

            TextareaField::make('bio', 'Bio')->onlyOnDetails(),

            TextField::make('email', 'Email')->displayOnIndexUsing(function ($value) {
                return "<a href='mailto:$value'>$value</a>";
            })->type('email')->sortable(),
        ];
    }

配置您的资源

您可以通过在您的资源类上设置一些属性来配置您的资源。

    /**
     * @var string The title will be used as your resource name in the ui
     */
    protected $title = "Users";

    /**
     * @var string[]
     */
    protected $searchColumns = ['id', 'name'];

    /**
     * @var string used to show resource value in relationship
     */
    protected $displayColumn = 'name';
    
    
    /** @var int Number of records per page */
    protected $perPage = 38;
    
    /** @var bool Determines if a resource should be shown in sidebar */
    protected $displayInSidebar = true;
    
    /**
     * @var bool Determines if a resource can be exported in excel format.
     */
    protected $exportable = true;

如果您想自定义每个不同屏幕(索引页面、编辑页面、详情页面等)应显示的标题,您可以在您的资源中定义 configure 方法。例如

    // use Oza75\LaravelHubble\Configuration\Configuration;
    // use Oza75\LaravelHubble\Configuration\ScreenConfiguration;
    
    
    public function configure(Configuration $configuration)
    {
        $configuration->details(function (ScreenConfiguration $configuration, User $user) {
            $configuration->setTitle("User #". $user->id);
        });
    }

注册您的资源

默认情况下,Hubble 将自动注册您在 app/Hubble 文件夹下的所有资源。

只需转到 http://yourapp.tld/hubble,您将看到我们添加的新用户资源。

您可以在配置文件中自定义 Hubble 必须在哪个文件夹中查找您的资源。自动注册在开发仪表板时非常有用,但在生产中您可能禁用它以提高性能。

在您的 app/Providers/HubbleServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Foundation\Auth\User;
use Oza75\LaravelHubble\HubbleServiceProvider as BaseProvider;

class HubbleServiceProvider extends BaseProvider
{
    /**
     * Determines if hubble should detects automatically
     * resources under Hubble resource folder. This is useful when you are
     * developing but should be disable in production
     *
     * @var bool
     */
    protected $autoRegistration = false; // set to false to disable auto registration 

    /**
     * List of resource Hubble should register. Should be used
     * when you set autoRegistration = false. Optionally you can
     * define a resource method in this class to bypass this property.
     *
     * @var array
     */
    protected $resources = [
        // add your resources manually here
        UserResource::class,
    ];

    /**
     * Determines if a given user can access to hubble dashboard.
     * By default every user can access to hubble
     *
     * @param User $user
     * @return bool
     */
    public function authorizesAccess(User $user): bool
    {
        return parent::authorizesAccess($user);
    }
}

操作

操作用于对一个或多个 Eloquent 模型执行自定义任务。您可以使用以下命令生成操作:

php artisan hubble:action ActiveUsers

此命令将在 app/Hubble/Actions 下生成一个新的 ActiveUsers

<?php

namespace App\Hubble\Actions;

use App\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\LazyCollection;
use Oza75\LaravelHubble\Action;

class ActiveUsers extends Action
{
    /**
     * @var string the title of this action
     */
    protected $title = 'ActiveUsers';

    /**
     * @var string the confirmation message to warn user before running this action. Set to null to disable it
     */
    protected $confirmationMessage = 'Do you really want to perform this action ?';

    /**
     * Handle your action
     *
     * @param LazyCollection $collection
     * @param Builder $query
     * @return string
     */
    public function handle(LazyCollection $collection, Builder $query)
    {
        $query = $query->newQuery();

        $collection->each(function (User $user) use ($query) {
            $query->orWhere('id', $user->id);
        });

        $query->update(['is_active' => true]);

        return "Utilisateurs activé avec succès !";
    }

    /**
     * @param \Illuminate\Foundation\Auth\User $user
     * @param Model|null $model
     * @return bool
     */
    public function can(\Illuminate\Foundation\Auth\User $user, ?Model $model = null): bool
    {
        return true;
    }

    protected function icon()
    {
        return asset('images/lock.svg');
    }
}

title 属性包含将在用户界面中显示的操作名称

handle 方法中,您可以执行您的操作。在我们的例子中,假设我们的用户表有一个 active 列,它确定用户是否活跃。

    /**
     * Handle your action
     *
     * @param $ids
     * @return void
     */
    public function handle($ids)
    {
        User::query()->whereIn('id', $ids)->update(['active' => true]);
    }

当您创建操作时,您可以在资源中添加它。

    /**
     * Register all actions that the user resource have
     *
     * @return Action[] array of actions
     */
    public function actions()
    {
        return [
            DeleteAction::make(),
            new ActiveUsers(),

        ];
    }

过滤器

如名称所示,过滤器用于过滤您的数据,并仅显示满足某些条件的数据。向资源中添加过滤器的有许多方法

  • 第一种方式(最简单的方式)
    /**
     * Register all filters that the user resource have
     *
     * @return Filter[] array of filters
     */
    public function filters()
    {
        return [
            Filter::make('is_active', 'Only Active Users', ['Yes' => 1, 'No' => 0]),
        ];
    }

Filter::make的第一个参数是数据库中的列。第二个参数是标题,然后是第三个选项数组。

选项参数是一个关联数组,键是标签,值是选项的值。您还可以传递一个URL,其中应该获取选项,或一个自定义数组。在这些情况下,您可以使用setValueKey(string $key)setTextKey(string $key)来设置valueKey和textKey。

例如

   /**
    * Register all filters that the user resource have
    *
    * @return Filter[] array of filters
    */
   public function filters()
   {
       return [
           Filter::make('is_active', 'Users Status', [ 
               ['name' => 'All', 'value' => null], 
               ['name' => 'Active', 'value' => 1], 
               ['name' => 'Non active', 'value' => 0]
           ])->setValueKey('value')->setTextKey('name'),
       ];
   }

另一个示例

    /**
     * Register all filters that the user resource have
     *
     * @return Filter[] array of filters
     */
    public function filters()
    {
        return [
            Filter::make('state', 'Users State', "https://restcountries.eu/rest/v2/all")
                ->setValueKey('alpha3Code')
                ->setTextKey('name')
                ->searchable('Start typing a state...'),
        ];
    }
  • 定义过滤器(更强大)的另一种方式
    /**
     * Register all filters that the user resource have
     *
     * @return Filter[] array of filters
     */
    public function filters()
    {
        return [
            Filter::make('state', 'Users State', "https://restcountries.eu/rest/v2/all")
                ->setValueKey('alpha3Code')
                ->setTextKey('name')
                ->setHandler(function (Builder $builder, $value) {
                    $builder->whereHas('state', function ($query) use ($value) {
                        $query->where('code', $value);
                    });
                }),
        ];
    }

使用这种方法,您可以使用setHandler方法传递一个可调用的函数,该函数将查询构建器作为第一个参数,并将过滤器值作为参数,您可以添加任何想要的where子句

  • 最后一种方式是生成一个新的过滤器类。
php artisan hubble:filter MyCustomFilter

此命令将在app/Hubble/Filters下生成一个新的过滤器类。

<?php

namespace App\Hubble\Filters;

use Illuminate\Database\Eloquent\Builder;
use Oza75\LaravelHubble\Filter;

class MyCustomFilter extends Filter
{
    /**
     * @var string the title of your filter that will be shown on the ui.
     */
    protected $title = 'My custom filter';

    /**
     * @var string the VueJs component that will be used to display this filter
     */
    protected $component = 'hubble-checkbox-filter';

    /**
     * Apply your filter
     *
     * @param Builder $query
     * @param $value
     * @return void
     */
    public function handle(Builder $query, $value)
    {
        // apply your filter here. 
        return null;
    }

    /**
     * Return all options for this filter
     *
     * @return array
     */
    public function options()
    {
        // first way
        return ['Option 1' => 1, 'Option 2' => 2]; // the key is the label and the value is the option value
        // second way
        return [
                    ['name' => 'Option 1', 'value' => 1],
                    ['name' => 'Option 2', 'value' => 2],
               ]; 
        // third way
        return "https://restcountries.eu/rest/v2/all";
        
        // do not forget to use `setValueKey(string $key)` and `setTextKey(string $key)` in the constructor of this class
        // or when instantiating this class to set the value key and the text key

    }
}

您还可以使用自定义VueJs组件生成过滤器。

php artisan hubble:filter MyCustomFilter --custom

这将在resources/hubble/components/filters/my-custom-filter.vue下生成一个VueJs组件。

字段

字段用于显示您的数据。基本Field类可以用于创建字段。任何类型的字段都扩展了这个类。

\Oza75\LaravelHubble\Field::make('column', 'title');
  • 可排序
\Oza75\LaravelHubble\Field::make('column', 'title')->sortable(); // now this field can be used to sort your data

您还可以告诉Hubble默认情况下使用某个字段来对数据进行排序。

\Oza75\LaravelHubble\Field::make('column', 'title')->sortable(true, 'desc');

自定义显示

有一些方法可以用来自定义您想要在仪表板的不同部分中显示的字段值。

  • displayUsing
  • displayOnIndexUsing
  • displayOnDetailsUsing
  • displayOnFormsUsing
  • displayWhenEditingUsing
  • displayWhenCreatingUsing

displayUsing方法自定义了仪表板所有部分的显示。

所有这些方法都有相同的签名。

\Oza75\LaravelHubble\Field::make('fullname', 'Full Name')->displayUsing(function ($value, $resource) {
    return $resource->first_name . ' '. $resource->last_name; // in this case resource is a User model
});

\Oza75\LaravelHubble\Field::make('email', 'Email')->displayOnIndexUsing(function ($value) {
    return "<a href='mailto:$value'>$value</a>";
});

可见性

Field提供了一些方法,您可以使用它们来指定何时显示

  • hide : 将在所有屏幕上隐藏字段
  • hideOnIndex
  • hideOnForms
  • hideOnDetails
  • hideWhenCreating
  • hideWhenEditing
  • hideOnExport
  • showOnIndex
  • showOnDetails
  • showOnForm
  • showWhenCreating
  • showWhenEditing
  • showOnExport
  • onlyOnIndex
  • onlyOnDetails
  • onlyOnForms
  • onlyOnCreating
  • onlyOnEditing
  • onlyOnExport
\Oza75\LaravelHubble\TextField::make('email', 'Email')->hideOnIndex();

所有这些方法都可以传递一个闭包,该闭包将被用来在特定屏幕上隐藏或显示字段。

\Oza75\LaravelHubble\PasswordField::make('password', 'Change the password')->onlyOnForms(function (User $user, ?\Illuminate\Database\Eloquent\Model $model = null) {
        return $user->isAdmin() || ($model && $model->id === $user->id);
});

Hubble提供了许多类型的字段,但您也可以创建自己的。

  • TextField
  • BooleanField
  • NumberField
  • TextareaField
  • DateTimeField
  • SelectField
  • ColorField
  • FileField
  • ImageField
  • BelongsToField (关系字段)
  • HasManyField (关系字段)

TextField

用于显示文本字段。

\Oza75\LaravelHubble\Fields\TextField::make('email', 'Email');
  • text类型
\Oza75\LaravelHubble\Fields\TextField::make('email', 'Email')->type('email');

此类型将用于在表单中显示正确的输入类型。

  • limit
\Oza75\LaravelHubble\Fields\TextField::make('bio', 'Bio')->limit(100);

限制表格中应显示的字符数。

BooleanField

    \Oza75\LaravelHubble\Fields\BooleanField::make('active', 'Active ?')->text('Yes', 'No');

当此字段具有truefalse值时,text方法将设置要显示的文本。

NumberField

用于显示数字值

\Oza75\LaravelHubble\Fields\NumberField::make('articles_count', 'Articles');

TextareaField

用于显示长文本值

\Oza75\LaravelHubble\Fields\TextareaField::make('bio', 'Bio');

DateTimeField

用于显示日期值

\Oza75\LaravelHubble\Fields\DateTimeField::make('created_at', 'Created at');
  • 日期格式
\Oza75\LaravelHubble\Fields\DateTimeField::make('created_at', 'Created at')->format('Y-m-d at h:i');
  • 日期区域
\Oza75\LaravelHubble\Fields\DateTimeField::make('created_at', 'Created at')->setLocale('fr')->format('Y-m-d at h:i');

SelectField

\Oza75\LaravelHubble\Fields\SelectField::make('user_type', 'Type')->options(['Pro' => 'pro', 'Normal' => 'normal']);
  • 使用标签显示
\Oza75\LaravelHubble\Fields\SelectField::make('user_type', 'Type')
->options(['Pro' => 'pro', 'Normal' => 'normal'])
->displayUsingLabel();

ColorField

用于显示颜色

\Oza75\LaravelHubble\Fields\ColorField::make('primary_color', 'Color');
  • 使用十六进制值显示
\Oza75\LaravelHubble\Fields\ColorField::make('primary_color', 'Color')->displayUsingHex();

FileField

用于显示和上传文件

\Oza75\LaravelHubble\Fields\FileField::make('avatar', 'Avatar'),
  • multiple
\Oza75\LaravelHubble\Fields\FileField::make('avatar', 'Avatar')->multiple(),
  • max

限制文件数量

\Oza75\LaravelHubble\Fields\FileField::make('avatar', 'Avatar')->multiple()->max(5),

ImageField

用于显示图像和上传图像。

ImageField扩展自FileField,因此它具有FileField的所有方法,例如multiplemax

\Oza75\LaravelHubble\Fields\ImageField::make('avatar', 'Avatar'),

\Oza75\LaravelHubble\Fields\ImageField::make('avatar', 'Avatar')->multiple()->max(5),

BelongsToField

用于显示相关资源

  • 签名
\Oza75\LaravelHubble\Fields\BelongsToField::make('method_name', 'related_class', 'Title');

第一个参数是名称关系方法。假设在我们的 User 模型中有一个指向 City 模型的 belongsTo 方法。

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function city() {
        return $this->belongsTo(City::class);
    }

然后在我们的资源中添加这个关系

\Oza75\LaravelHubble\Fields\BelongsToField::make('city', CityResource::class);

HasManyField

用于显示相关资源

  • 签名
\Oza75\LaravelHubble\Fields\BelongsToField::make('method_name', 'related_class', 'Title');

BelongsToField 类似,HasManyField 将关系方法名称作为其第一个参数。

\Oza75\LaravelHubble\Fields\HasManyField::make('roles', RoleResource::class, 'User Roles');

创建自定义字段

您可以通过此命令创建自定义字段

php artisan hubble:field ColorField 

您也可以使用此命令生成具有自定义组件的新字段

php artisan hubble:field ColorField --custom

这将在 resources/hubble/components/fields/color 下为您的字段创建新的 VueJs 组件

使用此命令构建新组件

npm run hubble:watch

npm run hubble:prod

php artisan hubble:field 将在 app/Hubble/Fields 下生成新的字段类

<?php

namespace App\Hubble\Fields;

use Oza75\LaravelHubble\Field;
use Oza75\LaravelHubble\HubbleResource;

class ColorField extends Field
{
  /**
     *  Register your vuejs components
     */
    protected function registerComponents()
    {
        parent::registerComponents();

        $this->components = [
            'index' => 'index-text-field',
            'editing' => 'edit-text-field',
            'creating' => 'edit-text-field',
            'details' => 'show-text-field'
        ];
    }

    /**
     * This hook is called when the field is ready to work.
     * Basically it will just set the resource within your field is added.
     * So if you have some attributes to add  or actions that depends on the resource
     * this is where you should do it.
     *
     * @param HubbleResource $resource
     */
    public function prepare(HubbleResource $resource)
    {
        parent::boot($resource);

        // do action that depends on the resource within this field is added
    }

}

规则

您可以通过在每个字段上设置规则来自动验证表单数据。

\Oza75\LaravelHubble\Fields\TextField::make('email', 'Email')->rules('required|email|max:255');

还有每个 creationediting 屏幕的 rules 方法

  • rulesWhenUpdating 将仅定义更新时的规则
  • rulesWhenCreating 将仅定义创建时的规则

警告:规则方法还不能接受验证对象(如规则类)或闭包,但任何 Pull Request 都是受欢迎的。

对于前端交互,您可以在 resources/hubble/rules.js 中设置一个处理程序,以自动验证字段值。如果没有,当用户填写表单时,将发送一个 ajax 请求到后端以检查值是否有效。

// this method must return a boolean, a string or a promise (for validations that need to make ajax requests) 
export const string = function (value, fieldName) {
    if (typeof value !== "string") {
        // For localization purposes your laravel validation language file is injected into the javascript window,
        // then you can use the `window.trans` method to return a translated string
        return window.trans('validation.string', {attribute: fieldName})
    }

    return true;
}

授权

授权用于限制对仪表板某些屏幕的访问。内部,它主要使用 Laravel Authorization Gate

您只需要为您的资源创建一个 Laravel Policy,这将控制哪个用户可以访问或无法访问特定屏幕。

例如,假设我有一个 Post 模型

php artisan make:policy PostPolicy --model=Post

这将在 app/Policies 下生成一个新的 Laravel Policy

<?php

namespace App\Policies;

use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    public function before(User $user)
    {
        // bypass all authorization check when user is admin
        if ($user->isAdmin()) {
            return true;
        }
    }

    /**
     * Determine whether the user can view any models.
     *
     * @param \App\User $user
     * @return mixed
     */
    public function viewAny(User $user)
    {
        return true; // Anyone can see `the index table`. You can also return false to remove the hubble' PostResource in sidebar.
    }

    /**
     * Determine whether the user can view the model.
     *
     * @param \App\User $user
     * @param \App\Post $model
     * @return mixed
     */
    public function view(User $user, Post $model)
    {
        return true; // anyone can see the details screen.
    }

    /**
     * Determine whether the user can create models.
     *
     * @param \App\User $user
     * @return mixed
     */
    public function create(User $user)
    {
        return true; // anyone can create a new user
    }

    /**
     * Determine whether the user can update the model.
     *
     * @param \App\User $user
     * @param \App\Post $model
     * @return mixed
     */
    public function update(User $user, Post $model)
    {
        return $user->id === $model->user_id; // only the owner of the post can edit this post
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param \App\User $user
     * @param \App\Post $model
     * @return mixed
     */
    public function delete(User $user, Post $model)
    {
        return $user->id === $model->user_id; // only the owner of the post can delete this post
    }

    /**
     * Determine whether the user can restore the model.
     *
     * @param \App\User $user
     * @param \App\User $model
     * @return mixed
     */
    public function restore(User $user, User $model)
    {
        return false;
    }

    /**
     * Determine whether the user can permanently delete the model.
     *
     * @param \App\User $user
     * @param \App\User $model
     * @return mixed
     */
    public function forceDelete(User $user, User $model)
    {
        return false;
    }

    /**
    * Determines if the current user can attach users to post 
    * when using a HasManyField
    */
    public function attachUser(User $user) {
        return false;
    }

    /**
    * Determines if the current user can detach users to post 
    * when using a HasManyField
    */
    public function detachUser(User $user, Post $model) {
        return false;
    }

}

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 CHANGELOG

贡献

有关详细信息,请参阅 CONTRIBUTING

安全

如果您发现任何安全相关的问题,请通过电子邮件 abouba181@gmail.com 而不是使用问题跟踪器。

鸣谢

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件

Laravel 包模板

此包是使用 Laravel 包模板 生成的。