Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Linkable Laravel Package

novius/laravel-linkable

Manage “linkable” Eloquent models in Laravel: define per-model link configuration (URL callback or route), labels/groups/search, and query customization. Includes a Linkable Nova field plus publishable config and language files.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require novius/laravel-linkable
    

    Publish optional config and language files if needed:

    php artisan vendor:publish --provider="Novius\LaravelLinkable\LaravelLinkableServiceProvider" --tag=config
    php artisan vendor:publish --provider="Novius\LaravelLinkable\LaravelLinkableServiceProvider" --tag=lang
    
  2. Apply the Trait to a Model: Add the Linkable trait to your Eloquent model (e.g., Post) and define a linkableConfig() method:

    use Novius\LaravelLinkable\Traits\Linkable;
    
    class Post extends Model {
        use Linkable;
    
        public function linkableConfig(): LinkableConfig {
            return new LinkableConfig(
                routeName: 'post.show',
                routeParameterName: 'post',
                optionLabel: 'title',
                optionGroup: 'Content'
            );
        }
    }
    
  3. Define a Route: Ensure the route referenced in linkableConfig() exists in your routes/web.php:

    Route::get('/posts/{post}', [PostController::class, 'show'])->name('post.show');
    
  4. Use the Model Methods: Generate URLs dynamically:

    $post = Post::first();
    echo $post->url(); // Generates the route URL for the post
    echo $post->previewUrl(); // Generates a preview URL if configured
    
  5. Integrate with Nova/Filament (Optional): Add the Linkable field to your Nova resource or Filament form:

    // Nova Example
    Linkable::make('Related Post', 'related_post')
        ->optionsClasses([Post::class])
    

Implementation Patterns

Core Workflows

1. Model Linking

  • Attach/Detach Links: Use the linkable() relationship to manage links between models:

    $post = Post::find(1);
    $post->linkable()->attach(Post::find(2)); // Link to another post
    $post->linkable()->detach(Post::find(2)); // Remove the link
    
  • Query Linked Models: Retrieve models linked to or from another model:

    $linkedPosts = Post::find(1)->linkedTo; // Posts linked *to* this post
    $postsLinkedFrom = Post::find(1)->linkedFrom; // Posts *linking from* this post
    

2. URL Generation

  • Dynamic URLs: Leverage url() and previewUrl() for consistent URL generation:

    $url = $post->url(['locale' => 'fr']); // Generates URL with locale
    $previewUrl = $post->previewUrl(); // Generates preview URL if token exists
    
  • Custom URL Logic: Override the default route() behavior in your AppServiceProvider:

    Linkable::setRouteCallback(function (string $name, array $parameters = [], ?string $locale = null) {
        return route($name, $parameters, true, $locale);
    });
    

3. Nova/Filament Integration

  • Nova Field: Use the Linkable field to create relationships in the admin panel:

    Linkable::make('Author', 'author')
        ->optionsClasses([User::class])
        ->optionLabel('name')
        ->optionGroup('Users');
    
  • Filament Form: Add the Linkable component to forms:

    Linkable::make('Featured Post')
        ->setLinkableClasses([Post::class])
        ->setLocale(request()->locale);
    

4. Multi-Lingual Support

  • Locale-Aware Links: Configure resolveQuery and resolveNotPreviewQuery to filter by locale:

    resolveQuery: function (Builder $query) {
        $query->where('locale', app()->getLocale());
    },
    
  • Custom Locale Resolution: Override getLocale() in your model if locale isn’t stored directly:

    public function getLocale() {
        return $this->parent?->locale;
    }
    

5. Configuration

  • Autoload Models: Define directories or models to autoload in config/laravel-linkable.php:

    'autoload_models_in' => app_path('Models'),
    'linkable_models' => [Vendor\Model::class],
    
  • Route Overrides: Add custom route names for non-model links:

    'linkable_routes' => [
        'home' => 'Home Page',
    ],
    

Integration Tips

1. Validation

  • Prevent Circular Links: Add validation in linkableConfig():
    optionsQuery: function (Builder $query) {
        $query->whereNotIn('id', [1, 2, 3]); // Exclude specific IDs
    },
    

2. Access Control

  • Restrict Linking: Use middleware or policies to control who can link models:
    // Example: Only allow admins to link posts
    public function authorizeLink($user, $post) {
        return $user->isAdmin();
    }
    

3. Testing

  • Test Linking Logic: Write feature tests for link attachment and URL generation:
    public function test_link_attachment() {
        $post1 = Post::factory()->create();
        $post2 = Post::factory()->create();
    
        $post1->linkable()->attach($post2);
        $this->assertTrue($post1->linkedTo->contains($post2));
    }
    

4. Performance

  • Optimize Queries: Use with() to eager-load linked models:

    $posts = Post::with('linkedTo')->get();
    
  • Cache URLs: Cache generated URLs if they’re static:

    $url = Cache::remember("post_url_{$post->id}", now()->addHours(1), function () use ($post) {
        return $post->url();
    });
    

Gotchas and Tips

Pitfalls

1. Configuration Overrides

  • Issue: Forgetting to publish the config file can lead to missing autoloaded models or routes. Fix: Always publish the config after installation:
    php artisan vendor:publish --provider="Novius\LaravelLinkable\LaravelLinkableServiceProvider" --tag=config
    

2. Locale Mismatches

  • Issue: URLs generated without the correct locale if disable_localization is true or getLocale() isn’t implemented. Fix: Ensure getLocale() is defined in your model or set disable_localization to false in the config.

3. Circular References

  • Issue: Infinite loops when querying linked models if not handled properly. Fix: Use ->distinct() or limit query depth:
    $linkedPosts = Post::find(1)->linkedTo()->limit(10)->get();
    

4. Route Name Conflicts

  • Issue: Route names in linkableConfig() may conflict with existing routes. Fix: Use unique route names or override the routeCallback to handle conflicts.

5. Nova/Filament Field Not Showing

  • Issue: The Linkable field not appearing in Nova/Filament. Fix: Ensure the model is autoloaded or manually added to linkable_models in the config. Verify the optionLabel and optionGroup are correctly set.

Debugging Tips

1. Check URL Generation

  • Debug: Log the generated URL to verify parameters:
    dd($post->url(['extra' => 'param']));
    

2. Inspect Queries

  • Debug: Use Laravel Debugbar or toSql() to check the query being executed:
    $query = Post::query()->where('locale', app()->getLocale());
    dd($query->toSql(), $query->getBindings());
    

3. Validate Config

  • Debug: Ensure linkableConfig() is correctly defined and all required fields (optionLabel, optionGroup) are set.

4. Preview Token Issues

  • Debug: If previewUrl() returns null, verify the previewTokenField is correctly configured and the token exists in the database.

Extension Points

1. Custom Link Types

  • Extend: Add support for non-model links (e.g., external URLs) by extending the Linkable trait or creating a custom field.

2. Validation Rules

  • Extend: Add validation logic in optionsQuery or create a custom resolver:
    optionsQuery: function (Builder $query) {
        $query->where('published_at
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi