From f795f54c877dc89b7971fd66fc3a2f6eb81c4109 Mon Sep 17 00:00:00 2001 From: carly Date: Thu, 5 Sep 2024 10:35:13 +0800 Subject: [PATCH] Allow custom models --- README.md | 13 +- config/filament-field-group.php | 4 + src/Base/Manifests/ModelManifest.php | 125 ------------------ src/Base/Manifests/ModelManifestInterface.php | 36 ----- src/Facades/ModelManifest.php | 25 ---- src/FilamentFieldGroup.php | 118 +++++++++++++++++ src/FilamentFieldGroupServiceProvider.php | 11 +- src/Models/Contracts/Field.php | 6 +- src/Models/Contracts/FieldGroup.php | 11 +- src/Models/Field.php | 3 +- src/Supports/FieldGroupConfig.php | 10 +- 11 files changed, 153 insertions(+), 209 deletions(-) delete mode 100644 src/Base/Manifests/ModelManifest.php delete mode 100644 src/Base/Manifests/ModelManifestInterface.php delete mode 100644 src/Facades/ModelManifest.php diff --git a/README.md b/README.md index c6ad356..3f7d17e 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,15 @@ This is the contents of the published config file: ```php return [ 'enabled' => false, + 'models' => [ + 'field' => \SolutionForest\FilamentFieldGroup\Models\Field::class, + 'field_group' => SolutionForest\FilamentFieldGroup\Models\FieldGroup::class, + ], 'table_names' => [ 'fields' => 'advanced_fields', 'field_groups' => 'advanced_field_groups', ], ]; - ``` ## Usage @@ -159,13 +162,15 @@ $panel This section allows you to customize the model used for field groups in the Filament Field Group package. By replacing the default `FieldGroup` model with your own implementation, you can extend or modify its behavior to suit your application's needs. -To do this, use the `replace` method from the `ModelManifest` facade, specifying the original model and your custom model. Here's an example: +To do this, use the `setFieldGroupModelClass` or `setFieldModelClass` methods from the `FilamentFieldGroup` facade, specifying the original model and your custom model. Here's an example: ```php -\SolutionForest\FilamentFieldGroup\Facades\ModelManifest::replace( - \SolutionForest\FilamentFieldGroup\Models\Contracts\FieldGroup::class, +\SolutionForest\FilamentFieldGroup\Facades\FilamentFieldGroup::setFieldGroupModelClass( Your\Models\FieldGroup::class ); +\SolutionForest\FilamentFieldGroup\Facades\FilamentFieldGroup::setFieldModelClass( + Your\Models\Field::class +); ``` ## Testing diff --git a/config/filament-field-group.php b/config/filament-field-group.php index 5f2ad02..b55a08d 100644 --- a/config/filament-field-group.php +++ b/config/filament-field-group.php @@ -3,6 +3,10 @@ // config for SolutionForest/FilamentFieldGroup return [ 'enabled' => false, + 'models' => [ + 'field' => \SolutionForest\FilamentFieldGroup\Models\Field::class, + 'field_group' => SolutionForest\FilamentFieldGroup\Models\FieldGroup::class, + ], 'table_names' => [ 'fields' => 'advanced_fields', 'field_groups' => 'advanced_field_groups', diff --git a/src/Base/Manifests/ModelManifest.php b/src/Base/Manifests/ModelManifest.php deleted file mode 100644 index 129a304..0000000 --- a/src/Base/Manifests/ModelManifest.php +++ /dev/null @@ -1,125 +0,0 @@ -guessContractClass($modelClass); - $this->models[$interfaceClass] = $modelClass; - $this->bindModel($interfaceClass, $modelClass); - } - } - - /** - * {@inheritdoc} - */ - public function add(string $interfaceClass, string $modelClass): void - { - $this->validateClassIsEloquentModel($modelClass); - - $this->models[$interfaceClass] = $modelClass; - - $this->bindModel($interfaceClass, $modelClass); - } - - /** - * {@inheritdoc} - */ - public function replace(string $interfaceClass, string $modelClass): void - { - $this->add($interfaceClass, $modelClass); - } - - /** - * {@inheritdoc} - */ - public function get(string $interfaceClass, ?string $fallback = null): ?string - { - return $this->models[$interfaceClass] ?? $fallback; - } - - /** - * Get the default models for registration. - * - * @return array The array of default model classes. - */ - protected static function getDefaultModels(): array - { - return [ - Models\Field::class, - Models\FieldGroup::class, - ]; - } - - //region Helper methods - /** - * Bind a model to the interface in the container. - * - * @param string $interfaceClass The interface class to bind. - * @param string $modelClass The model class to bind. - */ - protected function bindModel(string $interfaceClass, string $modelClass): void - { - app()->bind($interfaceClass, $modelClass); - } - - /** - * Guess the contract class for a given model class. - * - * @param string $modelClass The model class to guess the contract for. - * @return string The guessed contract class name. - */ - protected function guessContractClass(string $modelClass): string - { - $class = new \ReflectionClass($modelClass); - - $shortName = $class->getShortName(); - $namespace = $class->getNamespaceName(); - - return "{$namespace}\\Contracts\\$shortName"; - } - - /** - * Guess the model class for a given contract. - * - * @param string $modelContract The model contract to guess the class for. - * @return string The guessed model class name. - */ - protected function guessModelClass(string $modelContract): string - { - $shortName = (new \ReflectionClass($modelContract))->getShortName(); - - return 'SolutionForest\\FilamentFieldGroup\\Models\\' . $shortName; - } - - /** - * Validate that a class is an Eloquent model. - * - * @param string $class The class to validate. - * - * @throws \InvalidArgumentException If the class is not a subclass of Model. - */ - private function validateClassIsEloquentModel(string $class): void - { - if (! is_subclass_of($class, Model::class)) { - throw new \InvalidArgumentException(sprintf('Given [%s] is not a subclass of [%s].', $class, Model::class)); - } - } - //endregion Helper methods -} diff --git a/src/Base/Manifests/ModelManifestInterface.php b/src/Base/Manifests/ModelManifestInterface.php deleted file mode 100644 index 9fede0c..0000000 --- a/src/Base/Manifests/ModelManifestInterface.php +++ /dev/null @@ -1,36 +0,0 @@ -guessModelContractClass($modelClass); + $this->models[$interfaceClass] = $modelClass; + $this->bindModel($interfaceClass, $modelClass); + } + } + + public function getFieldGroupModelClass(): string + { + $interfaceClass = \SolutionForest\FilamentFieldGroup\Models\Contracts\FieldGroup::class; + + return $this->getModelClass($interfaceClass); + } + + public function setFieldGroupModelClass($modelClass) + { + $interfaceClass = \SolutionForest\FilamentFieldGroup\Models\Contracts\FieldGroup::class; + + $this->validateClassIsEloquentModel($modelClass); + + config()->set('filament-field-group.models.field', $modelClass); + + $this->models[$interfaceClass] = $modelClass; + + $this->bindModel($interfaceClass, $modelClass); + } + + public function getFieldModelClass(): string + { + $interfaceClass = \SolutionForest\FilamentFieldGroup\Models\Contracts\Field::class; + + return $this->getModelClass($interfaceClass); + } + + public function setFieldModelClass($modelClass): void + { + $interfaceClass = \SolutionForest\FilamentFieldGroup\Models\Contracts\Field::class; + + $this->validateClassIsEloquentModel($modelClass); + + config()->set('filament-field-group.models.field', $modelClass); + + $this->models[$interfaceClass] = $modelClass; + + $this->bindModel($interfaceClass, $modelClass); + } + public function getFieldTypeOptions(): array { $fieldTypes = FilamentFieldGroupPlugin::get()->getFieldTypeConfigs(); @@ -143,4 +200,65 @@ public function getFieldTypeConfig($name, array | string $data = []) return null; } + + //region Helper methods + protected function replaceModelClass(string $interfaceClass, string $modelClass): void + { + switch ($interfaceClass) + { + case \SolutionForest\FilamentFieldGroup\Models\Contracts\FieldGroup::class: + $this->setFieldGroupModelClass($modelClass); + break; + case \SolutionForest\FilamentFieldGroup\Models\Contracts\Field::class: + $this->setFieldModelClass($modelClass); + break; + } + } + + protected function getModelClass(string $interfaceClass, ?string $fallback = null): ?string + { + return $this->models[$interfaceClass] ?? $fallback; + } + + /** + * Bind a model to the interface in the container. + * + * @param string $interfaceClass The interface class to bind. + * @param string $modelClass The model class to bind. + */ + protected function bindModel(string $interfaceClass, string $modelClass): void + { + app()->bind($interfaceClass, $modelClass); + } + + /** + * Guess the contract class for a given model class. + * + * @param string $modelClass The model class to guess the contract for. + * @return string The guessed contract class name. + */ + protected function guessModelContractClass(string $modelClass): string + { + $class = new \ReflectionClass($modelClass); + + $shortName = $class->getShortName(); + $namespace = $class->getNamespaceName(); + + return "{$namespace}\\Contracts\\$shortName"; + } + + /** + * Validate that a class is an Eloquent model. + * + * @param string $class The class to validate. + * + * @throws \InvalidArgumentException If the class is not a subclass of Model. + */ + private function validateClassIsEloquentModel(string $class): void + { + if (! is_subclass_of($class, Model::class)) { + throw new \InvalidArgumentException(sprintf('Given [%s] is not a subclass of [%s].', $class, Model::class)); + } + } + //endregion Helper methods } diff --git a/src/FilamentFieldGroupServiceProvider.php b/src/FilamentFieldGroupServiceProvider.php index f049d35..4d6c290 100644 --- a/src/FilamentFieldGroupServiceProvider.php +++ b/src/FilamentFieldGroupServiceProvider.php @@ -7,8 +7,6 @@ use Filament\Support\Facades\FilamentIcon; use Illuminate\Filesystem\Filesystem; use Livewire\Features\SupportTesting\Testable; -use SolutionForest\FilamentFieldGroup\Base\Manifests\ModelManifest; -use SolutionForest\FilamentFieldGroup\Base\Manifests\ModelManifestInterface; use SolutionForest\FilamentFieldGroup\Testing\TestsFilamentFieldGroup; use Spatie\LaravelPackageTools\Commands\InstallCommand; use Spatie\LaravelPackageTools\Package; @@ -56,15 +54,10 @@ public function configurePackage(Package $package): void } } - public function registeringPackage(): void - { - $this->app->singleton(ModelManifestInterface::class, fn () => $this->app->make(ModelManifest::class)); - - \SolutionForest\FilamentFieldGroup\Facades\ModelManifest::register(); - } - public function packageBooted(): void { + \SolutionForest\FilamentFieldGroup\Facades\FilamentFieldGroup::registerModels(); + // Asset Registration FilamentAsset::register( $this->getAssets(), diff --git a/src/Models/Contracts/Field.php b/src/Models/Contracts/Field.php index 4c40a14..7a5ace3 100644 --- a/src/Models/Contracts/Field.php +++ b/src/Models/Contracts/Field.php @@ -2,6 +2,10 @@ namespace SolutionForest\FilamentFieldGroup\Models\Contracts; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Spatie\EloquentSortable\Sortable; -interface Field extends Sortable {} +interface Field extends Sortable +{ + public function group(): BelongsTo; +} diff --git a/src/Models/Contracts/FieldGroup.php b/src/Models/Contracts/FieldGroup.php index c02b81f..f6dd8e9 100644 --- a/src/Models/Contracts/FieldGroup.php +++ b/src/Models/Contracts/FieldGroup.php @@ -2,6 +2,15 @@ namespace SolutionForest\FilamentFieldGroup\Models\Contracts; +use Illuminate\Database\Eloquent\Relations\HasMany; use Spatie\EloquentSortable\Sortable; -interface FieldGroup extends Sortable {} +interface FieldGroup extends Sortable +{ + public function fields(): HasMany; + + /** + * @return \Filament\Forms\Components\Component + */ + public function toFilamentComponent(); +} diff --git a/src/Models/Field.php b/src/Models/Field.php index 0a65acf..2b8eb8a 100644 --- a/src/Models/Field.php +++ b/src/Models/Field.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use SolutionForest\FilamentFieldGroup\Models\Contracts\Field as FieldContact; use SolutionForest\FilamentFieldGroup\Supports\FieldGroupConfig; use Spatie\EloquentSortable\SortableTrait; @@ -31,7 +32,7 @@ public function __construct(array $attributes = []) $this->setTable(FieldGroupConfig::getFieldTableName()); } - public function group() + public function group(): BelongsTo { return $this->belongsTo(FieldGroupConfig::getFieldGroupModelClass(), 'group_id'); } diff --git a/src/Supports/FieldGroupConfig.php b/src/Supports/FieldGroupConfig.php index 4e54666..cbf6fbd 100644 --- a/src/Supports/FieldGroupConfig.php +++ b/src/Supports/FieldGroupConfig.php @@ -2,11 +2,7 @@ namespace SolutionForest\FilamentFieldGroup\Supports; -use SolutionForest\FilamentFieldGroup\Facades\ModelManifest; -use SolutionForest\FilamentFieldGroup\Models\Contracts\Field as FieldContract; -use SolutionForest\FilamentFieldGroup\Models\Contracts\FieldGroup as FieldGroupContract; -use SolutionForest\FilamentFieldGroup\Models\Field; -use SolutionForest\FilamentFieldGroup\Models\FieldGroup; +use SolutionForest\FilamentFieldGroup\Facades\FilamentFieldGroup; class FieldGroupConfig { @@ -17,7 +13,7 @@ public static function getFieldGroupTableName(): string public static function getFieldGroupModelClass(): string { - $class = ModelManifest::get(FieldGroupContract::class, FieldGroup::class); + $class = FilamentFieldGroup::getFieldGroupModelClass(); return self::ensureClassExists($class, 'FieldGroup model'); } @@ -29,7 +25,7 @@ public static function getFieldTableName(): string public static function getFieldModelClass(): string { - $class = ModelManifest::get(FieldContract::class, Field::class); + $class = FilamentFieldGroup::getFieldModelClass(); return self::ensureClassExists($class, 'Field model'); }