mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Caved and moved to separate resources and models as some resources could not be model-based.
This commit is contained in:
@@ -37,28 +37,22 @@ class User extends Authenticatable
|
||||
}
|
||||
```
|
||||
|
||||
### Define a Resource
|
||||
### Create a Resource
|
||||
|
||||
To define a Resource Model, add the `Filament\Traits\FilamentResource` trait to your model.
|
||||
|
||||
> Make note of the properties and methods added to the model example below for how to configure a resource.
|
||||
To define a Resource, create a new resource file in `app/Filament/Resources` like the following `Page.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Filament\Traits\FilamentResource;
|
||||
use Filament\FilamentResource;
|
||||
use App\Http\Livewire\Pages\Index;
|
||||
// use App\Http\Livewire\Pages\Show;
|
||||
|
||||
class Page extends Model
|
||||
class Page extends FilamentResource
|
||||
{
|
||||
use FilamentResource;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public $label = 'Pages';
|
||||
public $label = 'My Pages'; // defaults to pluralized classname
|
||||
public $icon = 'heroicon-o-database';
|
||||
public $sort = 0;
|
||||
public $hideFromNav = false;
|
||||
@@ -70,8 +64,6 @@ class Page extends Model
|
||||
// 'show' => Show::class,
|
||||
];
|
||||
}
|
||||
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ return [
|
||||
|
||||
'features' => [
|
||||
Features::registration(),
|
||||
Features::resourceModels()
|
||||
Features::resources()
|
||||
],
|
||||
|
||||
'models' => [
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Route;
|
||||
use Filament\Features;
|
||||
use Filament\Http\Controllers\{
|
||||
AssetController,
|
||||
ResourceModelController,
|
||||
ResourceController,
|
||||
};
|
||||
|
||||
// Assets
|
||||
@@ -32,8 +32,8 @@ Route::group(['middleware' => ['auth']], function () {
|
||||
// Dashboard
|
||||
Route::get('/', config('filament.livewire.dashboard'))->name('dashboard');
|
||||
|
||||
// Resource Models
|
||||
if (Features::hasResourceModels()) {
|
||||
Route::get('/resources/{model}/{action?}/{id?}', ResourceModelController::class)->name('resource');
|
||||
// Resources
|
||||
if (Features::hasResources()) {
|
||||
Route::get('/resources/{resource}/{action?}/{id?}', ResourceController::class)->name('resource');
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Contracts;
|
||||
|
||||
interface Resource
|
||||
{
|
||||
public function actions(): array;
|
||||
}
|
||||
+4
-4
@@ -26,13 +26,13 @@ class Features
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the application has resource models.
|
||||
* Determine if the application has resources.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasResourceModels()
|
||||
public static function hasResources()
|
||||
{
|
||||
return static::enabled(static::resourceModels());
|
||||
return static::enabled(static::resources());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ class Features
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function resourceModels()
|
||||
public static function resources()
|
||||
{
|
||||
return 'resourceModels';
|
||||
}
|
||||
|
||||
+11
-13
@@ -12,7 +12,7 @@ use Illuminate\Support\{
|
||||
Collection,
|
||||
HtmlString,
|
||||
};
|
||||
use Filament\Traits\FilamentResource;
|
||||
use Filament\FilamentResource;
|
||||
|
||||
class Filament
|
||||
{
|
||||
@@ -142,27 +142,25 @@ class Filament
|
||||
return $manifest[$key];
|
||||
}
|
||||
|
||||
public function getResourceModels(): Collection
|
||||
public function resources(): Collection
|
||||
{
|
||||
$app_path = config('filament.paths.models', app_path());
|
||||
$models = collect(File::allFiles($app_path))
|
||||
->map(function ($item) {
|
||||
$resources_path = config('filament.resources', app_path('Filament/Resources'));
|
||||
$models = collect(File::allFiles($resources_path))->map(function ($item) {
|
||||
$path = $item->getRelativePathName();
|
||||
$class = sprintf('\%s%s',
|
||||
Container::getInstance()->getNamespace(),
|
||||
strtr(substr($path, 0, strrpos($path, '.')), '/', '\\'));
|
||||
$class = sprintf(
|
||||
'\%s%s',
|
||||
Container::getInstance()->getNamespace().'Filament\\Resources\\',
|
||||
strtr(substr($path, 0, strrpos($path, '.')), '/', '\\')
|
||||
);
|
||||
|
||||
return $class;
|
||||
})
|
||||
->filter(function ($class) {
|
||||
})->filter(function ($class) {
|
||||
if (!class_exists($class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$reflection = new \ReflectionClass($class);
|
||||
return $reflection->isSubclassOf(Model::class) &&
|
||||
in_array(FilamentResource::class, class_uses_recursive($class)) &&
|
||||
!$reflection->isAbstract();
|
||||
return $reflection->isSubclassOf(FilamentResource::class) && !$reflection->isAbstract();
|
||||
})->mapWithKeys(function ($class) {
|
||||
return [class_basename($class) => $class];
|
||||
});
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Filament;
|
||||
|
||||
use Filament\Contracts\Resource;
|
||||
|
||||
abstract class FilamentResource implements Resource
|
||||
{
|
||||
public $icon = 'heroicon-o-document-text';
|
||||
public $sort = 0;
|
||||
public $hideFromNav = false;
|
||||
|
||||
public function actions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,9 @@ class FilamentServiceProvider extends ServiceProvider
|
||||
public function boot(): void
|
||||
{
|
||||
$this->bootModelBindings();
|
||||
$this->bootResources();
|
||||
$this->bootLoaders();
|
||||
$this->bootDirectives();
|
||||
$this->bootResourceModels();
|
||||
$this->bootResources();
|
||||
$this->bootCommands();
|
||||
$this->bootPublishing();
|
||||
}
|
||||
@@ -82,7 +82,7 @@ class FilamentServiceProvider extends ServiceProvider
|
||||
$this->app->bind('Filament\User', $models['user']);
|
||||
}
|
||||
|
||||
protected function bootResources(): void
|
||||
protected function bootLoaders(): void
|
||||
{
|
||||
$this->loadViewsFrom(__DIR__.'/../resources/views', 'filament');
|
||||
$this->loadViewComponentsAs(config('filament.prefix.component', 'filament'), config('filament.components', []));
|
||||
@@ -119,25 +119,23 @@ class FilamentServiceProvider extends ServiceProvider
|
||||
], 'filament-assets');
|
||||
}
|
||||
|
||||
protected function bootResourceModels(): void
|
||||
protected function bootResources(): void
|
||||
{
|
||||
if (Features::hasResourceModels()) {
|
||||
if (Features::hasResources()) {
|
||||
$this->app->booted(function () {
|
||||
$models = $this->app->filament->getResourceModels();
|
||||
|
||||
$models->each(function ($item, $key) {
|
||||
$model = $this->app->make($item);
|
||||
$this->app->filament->resources()->each(function ($item, $key) {
|
||||
$resource = $this->app->make($item);
|
||||
|
||||
if (array_key_exists('index', $model->actions())) {
|
||||
$route = route('filament.resource', ['model' => $key]);
|
||||
if (array_key_exists('index', $resource->actions())) {
|
||||
$route = route('filament.resource', ['resource' => $key]);
|
||||
|
||||
app(Navigation::class)->$key = [
|
||||
'path' => $route,
|
||||
'active' => $route.'*',
|
||||
'label' => $model->label ?? Str::plural($key),
|
||||
'icon' => $model->icon ?? 'heroicon-o-database',
|
||||
'sort' => $model->sort ?? 0,
|
||||
'hideFromNav' => $model->hideFromNav ?? false,
|
||||
'label' => $resource->label ?? Str::plural($key),
|
||||
'icon' => $resource->icon,
|
||||
'sort' => $resource->sort,
|
||||
'hideFromNav' => $resource->hideFromNav,
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
+6
-6
@@ -7,15 +7,15 @@ use Illuminate\Routing\Route;
|
||||
use Illuminate\View\View;
|
||||
use Filament;
|
||||
|
||||
class ResourceModelController extends Controller
|
||||
class ResourceController extends Controller
|
||||
{
|
||||
public function __invoke(Container $container, Route $route, string $model, string $action = 'index'): View
|
||||
public function __invoke(Container $container, Route $route, string $resource, string $action = 'index'): View
|
||||
{
|
||||
$model = Filament::getResourceModels()->get($model);
|
||||
abort_unless($model, 404);
|
||||
$resourceClass = Filament::resources()->get($resource);
|
||||
abort_unless($resourceClass, 400, __("`$resource` is not a valid resource."));
|
||||
|
||||
$component = collect(app($model)->actions())->get($action);
|
||||
abort_unless($component, 400, __("`$action` is not a valid resource action in `$model`"));
|
||||
$component = collect(app($resourceClass)->actions())->get($action);
|
||||
abort_unless($component, 400, __("`$action` is not a valid resource action in `$resourceClass`."));
|
||||
|
||||
return call_user_func((new $component), $container, $route);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Traits;
|
||||
|
||||
trait FilamentResource
|
||||
{
|
||||
public function actions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -89,7 +89,7 @@ abstract class TestCase extends OrchestraTestCase
|
||||
'prefix' => '',
|
||||
]);
|
||||
|
||||
$app['config']->set('filament.paths.models', __DIR__.'/Database/Models');
|
||||
$app['config']->set('filament.resources', __DIR__.'/Resources');
|
||||
$app['config']->set('auth.providers.users.model', User::class);
|
||||
$app['config']->set('filament.models.user', User::class);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user