think.studio / nova-thinkit
Laravel Nova small kit for quicker development.
1.7.1
2023-12-14 14:36 UTC
Requires
- php: ^8.1
- laravel/nova: ^4.14
- think.studio/laravel-simple-image-manager: ^3.4
- think.studio/nova-html-field: ^2.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.20
- orchestra/testbench: ^8.5
- phpunit/phpunit: ^10.2
- psalm/plugin-laravel: ^2.8
- think.studio/nova-flexible-content: ^4.0
- vimeo/psalm: ^5.13
README
Laravel Nova small kit for quicker development.
Installation
You can install the package via composer:
composer require think.studio/nova-thinkit # optional publish configs php artisan vendor:publish --provider="NovaThinKit\ServiceProvider" --tag="config" # optional publish translations php artisan vendor:publish --provider="NovaThinKit\ServiceProvider" --tag="lang"
Usage
Actions
Login to different guard
public function actions(NovaRequest $request) { return [ (new \NovaThinKit\Nova\Actions\LoginToDifferentGuard( route('dashboard.overview'), 'owners_web', __('Login to owner dashboard'), __('Are you sure you want to continue?'), )) // optional callback how to find correct user ->findIdUsing(fn (Contact $model) => Owner::query()->where('contact_id', $model->getKey())->first()?->getKey()) // other default method actions... ->canRun(fn ($request, Contact $model) => $model->role === "owner"), ]; }
Send reset password notification
use NovaThinKit\Nova\Actions\LoginToDifferentGuard; public function actions(NovaRequest $request) { return [ ( \NovaThinKit\Nova\Actions\SendResetPasswordEmail::make('contacts', __('Send reset password'), __('Are you sure you want to continue?'))) // optional callback how to find correct user ->findIdUsing(fn (Contact $model) => Owner::query()->where('contact_id', $model->getKey())->first()?->getKey()) // other default method actions... ->canRun(fn ($request, Contact $model) => $model->role === "owner"), ]; }
Filters
Dynamic Boolean filter
\NovaThinKit\Nova\Filters\DynamicBooleanFilter::make([ 'Active' => 'active', 'Paused' => 'paused', ] /* options */, 'status' /* column to filter */, 'Status' /* title */), // Useful with HumanReadable enums: \NovaThinKit\Nova\Filters\DynamicBooleanFilter::make(array_flip(CompanyStatus::options()), 'status', 'Status'),
Use filter for relation. For example add filter to Author to filter Posts:
\NovaThinKit\Nova\Filters\DynamicBooleanFilter::make(array_flip(CompanyStatus::options()), 'status', 'Posts Status')->forRelation('posts'),
Empty or null filed filter
\NovaThinKit\Nova\Filters\EmptyFieldFilter::make('post_title' /* column to filter */, 'Title' /* title */),
Use filter for relation. For example add filter to Author to filter Posts:
\NovaThinKit\Nova\Filters\EmptyFieldFilter::make('posts.post_title', 'Posts Title'),
BelongsTo filter
Filter by related belongsTo relation.
use NovaThinKit\Nova\Filters\BelongsToFilter; public function filters(NovaRequest $request) { return [ // type - this is belongsTo() relation method name new BelongsToFilter('type'), // or (new BelongsToFilter('type'))->setTitleKeyName('title'), // or (new BelongsToFilter('type'))->setFilterName('Filter by type'), ]; }
BelongsToMany filter
Filter by related belongsToMany relation.
public function filters(NovaRequest $request) { return [ \NovaThinKit\Nova\Filters\BelongsToManyFilter::make('tags') ->setTitleKeyName('name' /* label key name */) ->setFilterName('By tag'), ]; }
Metadata table
MetaFieldUpdater
If you have standalone table what contains meta values. You can use MetaFieldUpdater
to quicker update these values from main resource:
public function fields(NovaRequest $request) { $metaFieldUpdater = new \NovaThinKit\Nova\Helpers\MetaFieldUpdater( 'metaData' /* hasMany relation method name */, 'key' /* key name in neta table */, 'value' /* data name in neta table */ ); return [ $metaFieldUpdater->field( Select::make('University', 'university')->options(University::options()) ), // ALso works with flexible $metaFieldUpdater->field( Flexible::make('Ethos list', 'cf-numeric_list_with_team') ->limit(20) ->useLayout(EthosItemLayout::class), ), ]; }
Feature image functionality
Add interface and trait to model
class Page extends Model implements \NovaThinKit\FeatureImage\Models\WithFeatureImage { use \NovaThinKit\FeatureImage\Models\HasFeatureImage; // Optionally you can change default storage directory public function featureImageManagerDirectory(): string { return 'page/' . $this->getKey(); } // Optionally you can change default image-manager protected function createFeatureImageManager(?string $tag = null): ImageManager { if (!$this->featureImageManager) { $this->featureImageManager = FeatureImageManager::fromConfig([ 'disk' => 'feature-images', 'immutableExtensions' => [ '.svg', '.gif' ], 'original' => [ 'methods' => [ 'fit' => [ \Spatie\Image\Manipulations::FIT_CROP, 2800, 1800 ], 'optimize' => [], ], 'srcset' => '2800w', ], 'deletedFormats' => [], 'formats' => [ 'thumb' => [ 'methods' => [ 'fit' => [ \Spatie\Image\Manipulations::FIT_CONTAIN, 450, 300 ], 'optimize' => [], ], 'srcset' => '450w', ], ], ]); } if($tag === 'fooBar') { $this->featureImageManager->disk = 'baz'; } return $this->featureImageManager; } }
Add trait to resource
class Page extends Resource { use \NovaThinKit\FeatureImage\Nova\HasFeatureImage; // ... other methods public function fields(NovaRequest $request) { return [ // other fields $this->fieldFeatureImage(), ]; } }
Page templates (Dynamic fields based on template field)
Create template fields wrapper
namespace App\Nova\ResourceTemplates\Pages; use NovaThinKit\Nova\Helpers\MetaFieldUpdater; use NovaThinKit\Nova\ResourceTemplates\ResourceTemplate; class HomePageTemplate extends ResourceTemplate { public function fields(NovaRequest $request): array { $metaUpdater = new MetaFieldUpdater('meta', 'key', 'value'); return [ Text::make('Some Custom text', 'some_custom_text') ->hideWhenCreating() ->hideFromIndex() ->showOnPreview(), $metaUpdater->field( Text::make('Custom text', 'custom_text') ->hideWhenCreating() ->hideFromIndex() ->showOnPreview(), ), ]; } }
Add mapping
class AppServiceProvider extends ServiceProvider { public function boot() { \NovaThinKit\Nova\ResourceTemplates\TemplateFinder::templatesMap(Page::class, [ 'home' => HomePageTemplate::class, 'contact' => ContactPageTemplate::class, ]); } }
Finally, update resource
class Page extends Resource { use \NovaThinKit\Nova\ResourceTemplates\HasTemplate; public function fields(NovaRequest $request) { return [ ID::make()->sortable(), ...$this->templateFields($request), ]; } }