webfox/laravel-inertia-dataproviders

封装 Inertia 视图逻辑的数据提供者

v2.0.0 2024-09-20 03:46 UTC

This package is auto-updated.

Last update: 2024-09-20 03:48:28 UTC


README

Latest Version on Packagist Total Downloads

数据提供者封装 Inertia 视图逻辑,使您的控制器保持简洁。

安装

通过 composer 安装此包

composer require webfox/laravel-inertia-dataproviders

可选地发布配置文件

php artisan vendor:publish --provider="Webfox\InertiaDataProviders\InertiaDataProvidersServiceProvider"

我们假设您已经安装了 Laravel 的 Inertia 适配器。

此包解决了什么问题?

Laravel 的控制器本应保持简洁。我们已经有表单请求来提取验证和授权逻辑,而我们的显示逻辑在视图中,那么为什么我们还要坚持让控制器处理为这些视图获取数据呢?

这在引入了类似懒加载属性等概念的情况下,在 Inertia 应用中表现得尤为明显。

数据提供者将 Inertia 视图的数据组合提取到它们自己的类中。如果您的应用程序中的多个路由或控制器需要特定的数据,Inertia 数据提供者可能会非常有用。

不再需要 40 行的控制器方法来获取数据了!

用法

使用数据提供者

数据提供者利用了 Inertia::render 可以接受 Arrayable 的特性。它们也可以用作数据数组中的离散属性。

use App\Models\Demo;
use App\DataProviders\DemoDataProvider;

class DemoController extends Controller
{
    public function show(Demo $demo)
    {
        return Inertia::render('DemoPage', new DemoDataProvider($demo));
    }
    
    public function edit(Demo $demo)
    {
        return Inertia::render('DemoPage', [
          'some' => 'data',
          'more' => 'data',
          'demo' => new DemoDataProvider($demo),
        ]);
    }
}

数据提供者是什么样的?

数据提供者可以放在任何地方,但在这个例子中我们将使用 App/Http/DataProviders

最简单的数据提供者只是一个扩展 DataProvider 的类,任何公共方法或属性都将作为数据提供给页面。
一个功能齐全的数据提供者可能如下所示

<?php
declare(strict_types=1);

namespace App\Http\DataProviders;

use Inertia\LazyProp;
use App\Services\InjectedDependency;
use Webfox\InertiaDataProviders\DataProvider;

class DemoDataProvider extends DataProvider
{

    public function __construct(
        /*
         * All public properties are automatically available in the page
         * This would be available to the page as `demo`
         */
        public Demo $demo;
    )
    {
        /*
         * Data providers have a `staticData` property, which you can use to add any data that doesn't warrant a full
         * property or separate method
         */
        $this->staticData = [
            /*
             * This will be available to the page as `title`
             */
            'title' => $this->calculateTitle($demo),
        ];
    }
    
    /*
     * All public methods are automatically evaluated as data and provided to the page.
     * ALWAYS included on first visit, OPTIONALLY included on partial reloads, ALWAYS evaluated
     * This would be available to the page as `someData`.
     * Additionally these methods are resolved through Laravel's service container, so any parameters will be automatically resolved.
     */
    public function someData(InjectedDependency $example): array
    {
        return [
            'some' => $example->doThingWith('some'),
            'more' => 'data',
        ];
    }
    
    /*
     * If a method returns a `Closure` it will be evaluated as a lazy property.
     * ALWAYS included on first visit, OPTIONALLY included on partial reloads, ONLY evaluated when needed
     * Additionally the callback methods are resolved through Laravel's service container, so any parameters will be automatically resolved.
     * @see https://inertia.laravel.net.cn/partial-reloads#lazy-data-evaluation
     */
    public function quickLazyExample(): Closure
    {
        return function(InjectedDependency $example): string {
            return $example->formatName($this->demo->user->name);
        };
    }
    
    /*
     * If a method is typed to return a LazyProp, it will only be evaluated when requested following inertia's rules for lazy data evaluation
     * NEVER included on first visit, OPTIONALLY included on partial reloads, ONLY evaluated when needed
     * Additionally the lazy callback methods are resolved through Laravel's service container, so any parameters will be automatically resolved.
     * @see https://inertia.laravel.net.cn/partial-reloads#lazy-data-evaluation
     */
    public function lazyExample(): LazyProp
    {
        return Inertia::lazy(
            fn (InjectedDependency $example) => $example->aHeavyCalculation($this->demo)
        );
    }
    
    /*
     * `protected` and `private` methods are not available to the page
     */
    protected function calculateTitle(Demo $demo): string
    {
        return $demo->name . ' Demo';
    }

}

使用多个数据提供者

有时您可能需要返回多个数据提供者,DataProvider::collection 是您的方法。集合中的每个数据提供者都将被评估并合并到页面的数据中,来自数据提供者的后续值将覆盖早期数据提供者的值。

use App\Models\Demo;
use App\DataProviders\TabDataProvider;
use App\DataProviders\DemoDataProvider;

class DemoController extends Controller
{
    public function show(Demo $demo)
    {
        return Inertia::render('DemoPage', DataProvider::collection(
            new TabDataProvider(current: 'demo'),
            new DemoDataProvider($demo),
        ));
    }
}

您还可以根据条件将数据提供者包含在集合中

use App\Models\Demo;
use App\DataProviders\TabDataProvider;
use App\DataProviders\DemoDataProvider;
use App\DataProviders\EditDemoDataProvider;
use App\DataProviders\CreateVenueDataProvider;

class DemoController extends Controller
{
    public function show(Demo $demo)
    {
        return Inertia::render('DemoPage', DataProvider::collection(
            new TabDataProvider(current: 'demo'),
            new DemoDataProvider($demo),
        )->when($demo->has_venue, function (DataProviderCollection $collection) use($demo) {
            $collection->push(new CreateVenueDataProvider($demo));
        })
        ->unless($demo->locked, function (DataProviderCollection $collection) use($demo) {
            $collection->push(new EditDemoDataProvider($demo));
        }));
    }
}

或者您可以使用 DataProviderCollection::add 方法在稍后添加数据提供者到集合

use App\Models\Demo;
use App\DataProviders\TabDataProvider;
use App\DataProviders\DemoDataProvider;
use App\DataProviders\CreateVenueDataProvider;

class DemoController extends Controller
{
    public function show(Demo $demo)
    {
        $pageData = DataProvider::collection(
            new TabDataProvider(current: 'demo'),
            new DemoDataProvider($demo),
        );
        
        if($demo->has_venue) {
            $pageData->add(new CreateVenueDataProvider($demo));
        }

        return Inertia::render('DemoPage', $pageData);
    }
}

如果您需要将整个数据集作为数组返回,例如用于 JSON 响应,您可以使用 toNestedArray()

use App\Models\Demo;
use Illuminate\Http\Request;
use App\DataProviders\TabDataProvider;
use App\DataProviders\DemoDataProvider;
use App\DataProviders\CreateVenueDataProvider;

class DemoController extends Controller
{
    public function show(Request $request, Demo $demo)
    {
        return (new DemoDataProvider($demo))->toNestedArray();
    }
}

属性名称格式化

可以通过在配置文件中将 attribute_name_formatter 设置来配置属性名称格式。
该包包含三个格式化程序,位于命名空间 \Webfox\InertiaDataProviders\AttributeNameFormatters 下,但您可以自由创建自己的。

AsWritten

这是默认格式化程序。输出属性名称将与输入名称相同。例如,名为 $someData 的属性和名为 more_data() 的方法将在页面中作为 someDatamore_data 可用。

SnakeCase

此格式化程序将属性名称转换为 snake_case。
例如,名为 $someData 的属性和名为 more_data() 的方法将在页面中作为 some_datamore_data 可用。

CamelCase

此格式化程序将属性名称转换为 camelCase。
例如,名为 $someData 的属性和名为 more_data() 的方法将在页面中作为 someDatamoreData 可用。

变更日志

请参阅变更日志以获取有关最近变更的更多信息。

贡献

我们欢迎所有对项目做出贡献的人。

许可证

MIT 许可证 (MIT)。请参阅许可证文件以获取更多信息。