diff --git a/README.md b/README.md index 9eea86a..73ef5d8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A Nova tool to manage menus. * PHP >= 8.1 * Laravel Nova >= 4.0 -* Laravel Framework >= 9.0 | >= 10.0 | >= 11.0 +* Laravel Framework >= 9.0 | >= 10.0 | >= 11.0 > **NOTE**: These instructions are for Laravel >= 9.0 and Laravel Nova 4.0. If you are using prior version, please > see the [previous version's docs](https://github.com/novius/laravel-nova-menu/tree/3-x). @@ -83,67 +83,7 @@ php artisan vendor:publish --provider="Novius\LaravelNovaMenu\LaravelNovaMenuSer ### Manage internal link possibilities -**linkable_objects** - -You can add dynamic routes to `linkable_objects` array (in configuration file). - -Example with `App\Models\Foo` Model. - -In this example we have a route defined as following : - -```php -Route::get('foo/{slug}', 'FooController@show')->name('foo.show'); -``` - -First, you have to add the Model to `laravel-nova-menu.php` config file. - -```php -return [ - 'linkable_objects'=> [ - App\Models\Foo:class => 'foo.label', // foo.label is a translation key - ], - ... -]; -``` - -Then, you have to implements `Linkable` trait to the model. - -```php -namespace App\Models; - -use Illuminate\Database\Eloquent\Model; -use Novius\LaravelNovaMenu\Traits\Linkable; - -class Foo extends Model -{ - use Linkable; - - public function linkableUrl(): string - { - return route('foo.show', ['slug' => $this->slug]); - } - - public function linkableTitle(): string - { - return $this->name; - } -} -``` - -**linkable_routes** - -You can also add static routes to `linkable_routes` array (in configuration file). - -Example with a route with name `home`. - -```php -return [ - 'linkable_objects'=> [ - 'contact' => 'contact.page', // contact.page is a translation key - ], - ... -]; -``` +Laravel Nova Menu uses [Laravel Linkable](https://github.com/novius/laravel-linkable) to manage linkable routes and models. Please read the documentation. ### Customize tree passed to the view diff --git a/UPGRADE.md b/UPGRADE.md index 5bbb4ed..4a62246 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,12 @@ # Nova menu manager Upgrade guide +## From v6 to v7 + +Laravel Nova Menu now uses [Laravel Linkable](https://github.com/novius/laravel-linkable) to manage linkable routes and models. Please read the documentation. + +* The config keys `linkable_objects` and `linkable_routes` are now delegate to Laravel Linkable. You can remove them from the config file `laravel-nova-menu` and report their value in the new `laravel-linkable` config file. +* Modify all your models using \Novius\LaravelNovaMenu\Traits\Linkable trait to use the new \Novius\LaravelLinkable\Traits\Linkable. You can remove `linkableUrl` and `linkableTitle` method of your model. + ## From v5 to v6 The blade directive `@menu` is deprecated and will be removed in future versions. Use blade component `` instead. diff --git a/composer.json b/composer.json index 550ffe1..5c28a21 100644 --- a/composer.json +++ b/composer.json @@ -18,13 +18,13 @@ "php": "^8.1", "laravel/nova": "^4.0", "illuminate/support": "^9.0 | ^10.0 | ^11.0", + "novius/laravel-linkable": "^1.0", "novius/laravel-nova-order-nestedset-field": "^4.0", "spatie/laravel-sluggable": "^3.4.0" }, "require-dev": { "laravel/pint": "^1.7", - "orchestra/testbench": "^7.4.0", - "phpunit/phpunit": "^9.3.3" + "orchestra/testbench": "^9.2" }, "autoload": { "psr-4": { @@ -44,11 +44,11 @@ } }, "scripts": { - "fmt": [ + "cs-fix": [ "./vendor/bin/pint -v" ], "lint": [ - "@composer fmt -- --test" + "@composer cs-fix -- --test" ], "test": "vendor/bin/phpunit --verbose --log-junit phpunit.log.xml" }, @@ -56,6 +56,10 @@ { "type": "composer", "url": "https://nova.laravel.com" + }, + { + "type": "vcs", + "url": "git@github.com:novius/laravel-linkable.git" } ], "config": { diff --git a/config/laravel-nova-menu.php b/config/laravel-nova-menu.php index f538e95..8ad79ad 100644 --- a/config/laravel-nova-menu.php +++ b/config/laravel-nova-menu.php @@ -5,32 +5,6 @@ use Novius\LaravelNovaMenu\Resources\MenuItem; return [ - /* - * Entities linkable by a menu item. For instance "Pages". - * So the pages of your application will be listed and linkable by an item menu. - * - * It must contain pairs of: - * full-class-name => prefix for the list in backoffice - * - * The "prefix for the list in backoffice" will be the parameter of the laravel function trans(). - * For instance: App\Models\Page::class => 'path.to.translation.page', - * - * Warning: The models listed below must use the trait Linkable and optionally override methods to suit their needs. - */ - - 'linkable_objects' => [], - - /* - * Sometimes you need to link items that are not objects. - * - * This config allows you to link routes. - * For instance: 'contact' => 'page.contact' - * - * "contact" will be the parameter of the laravel function route(). - * "page.contact" will be the parameter of the laravel function trans(). - */ - 'linkable_routes' => [], - /* |-------------------------------------------------------------------------- | Locales diff --git a/database/migrations/2024_08_06_124510_update_menu_items_internal_link.php b/database/migrations/2024_08_06_124510_update_menu_items_internal_link.php new file mode 100644 index 0000000..f1d3e1b --- /dev/null +++ b/database/migrations/2024_08_06_124510_update_menu_items_internal_link.php @@ -0,0 +1,18 @@ +whereLike('internal_link', 'linkable_route%') + ->update(['internal_link' => DB::raw("REPLACE(`internal_link`, 'linkable_route', 'route')")]); + + DB::table('nova_menu_items') + ->whereLike('internal_link', 'linkable_object%') + ->update(['internal_link' => DB::raw("REPLACE(`internal_link`, 'linkable_object:', '')")]); + } +}; diff --git a/src/Helpers/MenuHelper.php b/src/Helpers/MenuHelper.php index bdda645..dac4235 100644 --- a/src/Helpers/MenuHelper.php +++ b/src/Helpers/MenuHelper.php @@ -5,60 +5,18 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Route; use Novius\LaravelNovaMenu\Models\Menu; use Novius\LaravelNovaMenu\Models\MenuItem; -use Novius\LaravelNovaMenu\Traits\Linkable; class MenuHelper { - /** - * Returns a sorted array of linkable items and routes. - * This collection is used in the back office to feed a select list. - * This select list is intended for adding new menu items. - */ - public static function links(): array - { - $links = []; - $linkableObjects = config('laravel-nova-menu.linkable_objects', []); - foreach ($linkableObjects as $class => $translation) { - /** @var Linkable $class */ - $links[] = $class::linkableItems(trans($translation)); - } - - $linkableRoutes = config('laravel-nova-menu.linkable_routes', []); - foreach ($linkableRoutes as $routeName => $translation) { - if (Route::has($routeName)) { - $links[] = static::linkableRoute($routeName, trans($translation)); - } - } - - $links = array_merge(...$links); - asort($links); - - return $links; - } - - /** - * Returns an array of well-formed linkable route. - * Check out the config file or the readme file to know more about linkable routes. - * - * @overridable - */ - protected static function linkableRoute(string $routeName, string $translation): array - { - return [ - 'linkable_route:'.$routeName => $translation, - ]; - } - /** * Display menu from its slug * Fallback to menu with current application locale * * You can append '|no-locale-fallback' to slug if you want to skip the default fallback */ - public static function displayMenu(Menu|string $slug_or_menu, string $view = null, bool $localeFallback = true): string + public static function displayMenu(Menu|string $slug_or_menu, ?string $view = null, bool $localeFallback = true): string { if ($slug_or_menu instanceof Menu) { $menu = $slug_or_menu; diff --git a/src/Models/MenuItem.php b/src/Models/MenuItem.php index be8478b..9256ff9 100644 --- a/src/Models/MenuItem.php +++ b/src/Models/MenuItem.php @@ -6,9 +6,8 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\Route; -use Illuminate\Support\Str; use Kalnoy\Nestedset\NodeTrait; +use Novius\LaravelLinkable\Facades\Linkable; use Novius\LaravelNovaOrderNestedsetField\Traits\Orderable; /** @@ -125,18 +124,7 @@ public function href(): string } if (! empty($this->internal_link)) { - $infos = explode(':', $this->internal_link); - if (Str::startsWith($this->internal_link, 'linkable_route')) { - if (Route::has($infos[1])) { - $href = route($infos[1]); - } - } elseif (Str::startsWith($this->internal_link, 'linkable_object')) { - $className = $infos[1]; - $item = $className::find($infos[2]); - if (! empty($item->id)) { - $href = $item->linkableUrl(); - } - } + $href = Linkable::getLink($this->internal_link); } return $href; diff --git a/src/Resources/MenuItem.php b/src/Resources/MenuItem.php index 4e0cabd..c5dfba8 100755 --- a/src/Resources/MenuItem.php +++ b/src/Resources/MenuItem.php @@ -14,10 +14,11 @@ use Laravel\Nova\Fields\Select; use Laravel\Nova\Fields\Text; use Laravel\Nova\Http\Requests\NovaRequest; -use Novius\LaravelNovaMenu\Helpers\MenuHelper; +use Novius\LaravelLinkable\Nova\Fields\Linkable; use Novius\LaravelNovaMenu\Lenses\MenuItems; use Novius\LaravelNovaOrderNestedsetField\OrderNestedsetField; +/** @extends \Laravel\Nova\Resource */ class MenuItem extends Resource { /** @@ -143,9 +144,7 @@ public function fields(Request $request) return $this->linkTypeLabel(); })->exceptOnForms(), - Select::make(trans('laravel-nova-menu::menu.internal_link'), 'internal_link') - ->searchable() - ->options(MenuHelper::links()) + Linkable::make(trans('laravel-nova-menu::menu.internal_link'), 'internal_link') ->hideFromIndex() ->hideFromDetail() ->dependsOn( diff --git a/src/Traits/Linkable.php b/src/Traits/Linkable.php deleted file mode 100644 index e9493fa..0000000 --- a/src/Traits/Linkable.php +++ /dev/null @@ -1,57 +0,0 @@ -mapWithKeys(function ($item) use ($prefix) { - $objectId = 'linkable_object:'.get_class($item).':'.$item->linkableId(); - $title = static::linkableLabel($item->linkableTitle(), $prefix); - - return [ - $objectId => $title, - ]; - })->toArray(); - } - - /** - * Returns the id of the linkable item. - * - * @overridable - */ - protected function linkableId(): string - { - $primaryKey = $this->getKeyName(); - - return $this->{$primaryKey}; - } - - /** - * Returns a label, optionally prefixed. - */ - protected static function linkableLabel(string $name, string $prefix = ''): string - { - $label = $name; - if ($prefix) { - $label = implode(' - ', [$prefix, $name]); - } - - return $label; - } -}