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

Url Shortener Laravel Package

mosufy/url-shortener

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require mosufy/url-shortener
    

    Publish the config file:

    php artisan vendor:publish --provider="Mosufy\UrlShortener\UrlShortenerServiceProvider"
    
  2. Configuration Edit config/url-shortener.php to define:

    • Base URL for shortened links (e.g., http://short.example.com)
    • Custom slug length (default: 6)
    • Custom storage driver (default: database)
  3. First Use Case Generate a shortened URL:

    use Mosufy\UrlShortener\Facades\UrlShortener;
    
    $shortUrl = UrlShortener::shorten('https://laravel.com/docs');
    echo $shortUrl; // e.g., "http://short.example.com/abc123"
    
  4. Where to Look First

    • Facade: Mosufy\UrlShortener\Facades\UrlShortener (primary entry point)
    • Config: config/url-shortener.php (customize behavior)
    • Migrations: vendor/mosufy/url-shortener/database/migrations/ (if using DB driver)

Implementation Patterns

Core Workflows

  1. Generating Short URLs

    // Basic usage
    $shortUrl = UrlShortener::shorten('https://example.com');
    
    // Custom slug length (if configured)
    $shortUrl = UrlShortener::shorten('https://example.com', 8);
    
    // Force regeneration (if slug already exists)
    $shortUrl = UrlShortener::shorten('https://example.com', 6, true);
    
  2. Retrieving Original URLs

    $originalUrl = UrlShortener::getOriginalUrl('abc123');
    // or via route (if using web middleware)
    
  3. Custom Slugs

    $shortUrl = UrlShortener::shorten('https://example.com', null, false, 'my-custom-slug');
    
  4. Batch Processing

    $urls = ['https://example.com', 'https://google.com'];
    $shortUrls = UrlShortener::shortenBatch($urls);
    

Integration Tips

  • Middleware for Redirects Add to app/Http/Kernel.php:

    protected $routeMiddleware = [
        'shorten' => \Mosufy\UrlShortener\Http\Middleware\ShortenUrl::class,
    ];
    

    Route definition:

    Route::get('/{slug}', ['middleware' => 'shorten'])->name('short.url');
    
  • API Endpoints

    Route::post('/shorten', 'UrlShortenerController@shorten');
    Route::get('/{slug}', 'UrlShortenerController@redirect');
    
  • Custom Storage Extend the Mosufy\UrlShortener\Contracts\UrlShortenerRepository interface to implement a new storage driver (e.g., Redis, DynamoDB).

  • Event Listeners Listen for UrlShortened events to log or notify:

    UrlShortener::shorten('https://example.com');
    // Fires: Mosufy\UrlShortener\Events\UrlShortened
    

Gotchas and Tips

Pitfalls

  1. Slug Collisions

    • The package uses a random string by default. If you generate the same slug twice, the second URL will overwrite the first.
    • Fix: Use forceRegenerate: true or implement a custom slug generator.
  2. Database Driver Assumptions

    • The default migration assumes a urls table with id, slug, original_url, and created_at columns.
    • Fix: If using a custom table, override the UrlShortenerRepository binding in the service provider.
  3. Base URL Validation

    • The base URL must end with a trailing slash (/). Missing it causes redirect loops.
    • Fix: Ensure config/url-shortener.php has:
      'base_url' => 'http://short.example.com/',
      
  4. Case Sensitivity

    • Slugs are case-sensitive by default. ABC123 and abc123 are treated as different URLs.
    • Fix: Normalize slugs in your custom storage logic if needed.
  5. Rate Limiting

    • No built-in rate limiting. High traffic may cause collisions or performance issues.
    • Fix: Implement middleware or use a queue for batch processing.

Debugging Tips

  • Check Slug Existence

    if (UrlShortener::exists('abc123')) {
        // Slug already taken
    }
    
  • Log Shortened URLs Override the UrlShortenerRepository to log calls:

    public function save($slug, $originalUrl)
    {
        Log::info("Shortened URL: {$slug} -> {$originalUrl}");
        // ... original logic
    }
    
  • Test Locally Use a local base URL (e.g., http://short.test/) and configure your hosts file:

    127.0.0.1 short.test
    

Extension Points

  1. Custom Slug Generator Bind a custom generator in the service provider:

    $this->app->bind('url-shortener.slug-generator', function () {
        return new \App\Services\CustomSlugGenerator();
    });
    
  2. Analytics Middleware Extend the ShortenUrl middleware to track clicks:

    public function handle($request, Closure $next)
    {
        $slug = $request->slug;
        // Log click or increment counter
        return $next($request);
    }
    
  3. Custom Storage Implement the UrlShortenerRepository interface:

    class RedisUrlShortenerRepository implements UrlShortenerRepository
    {
        public function save($slug, $originalUrl)
        {
            Redis::set("url:{$slug}", $originalUrl);
        }
    
        public function find($slug)
        {
            return Redis::get("url:{$slug}");
        }
    }
    

    Bind it in the service provider:

    $this->app->bind('url-shortener.repository', function () {
        return new RedisUrlShortenerRepository();
    });
    
  4. Fallback for Missing Slugs Handle cases where a slug doesn’t exist:

    if (!$originalUrl = UrlShortener::getOriginalUrl('nonexistent')) {
        abort(404);
    }
    

Performance Quirks

  • Database Locking: High concurrency may cause timeouts when generating slugs. Use forceRegenerate sparingly.
  • Caching: Cache getOriginalUrl results if your use case allows it:
    $originalUrl = Cache::remember("url:{$slug}", now()->addHours(1), function () use ($slug) {
        return UrlShortener::getOriginalUrl($slug);
    });
    
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.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours