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

Uri Contracts Laravel Package

boson-php/uri-contracts

Framework-agnostic URI contracts for the Boson PHP ecosystem. Provides interface definitions for working with URIs in Boson and related packages, enabling consistent implementations and integrations across applications, windows, and webviews.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require boson-php/uri-contracts
    

    Ensure your project uses PHP 8.4+ and Laravel (or a non-Laravel PHP app).

  2. Understand the Core Interfaces: The package provides three primary interfaces:

    • UriInterface: Represents a URI as a string and supports type-safe conversion.
      use Boson\UriContracts\UriInterface;
      
      $uri = UriInterface::fromString('https://example.com/path?query=value');
      echo (string) $uri; // Outputs: https://example.com/path?query=value
      
    • UriBuilderInterface: Constructs URIs programmatically.
      use Boson\UriContracts\UriBuilderInterface;
      
      $builder = new class implements UriBuilderInterface {
          public function build(string $path, array $query = []): UriInterface {
              return UriInterface::fromString("https://example.com/$path?" . http_build_query($query));
          }
      };
      
    • UriStringable: Ensures a class can be converted to a URI string.
      use Boson\UriContracts\UriStringable;
      
      class MyClass implements UriStringable {
          public function __toString(): string {
              return 'https://example.com';
          }
      }
      
  3. First Use Case: Replace Hardcoded URLs in a Service Replace a service method that uses string URLs with the UriInterface:

    // Before
    public function getUserProfileUrl(int $userId): string {
        return "https://api.example.com/users/$userId";
    }
    
    // After
    public function getUserProfileUrl(int $userId): UriInterface {
        return UriInterface::fromString("https://api.example.com/users/$userId");
    }
    
  4. Leverage Laravel’s Facade with an Adapter (Optional) Create a simple adapter to bridge Laravel’s Url facade with UriInterface:

    use Boson\UriContracts\UriInterface;
    use Illuminate\Support\Facades\Url;
    
    class LaravelUriAdapter implements UriInterface {
        public function __construct(private string $url) {}
        public static function fromString(string $url): self {
            return new self($url);
        }
        public function __toString(): string {
            return Url::to($this->url);
        }
    }
    

Implementation Patterns

Common Workflows

1. URI Construction in Services

Use UriBuilderInterface to centralize URI logic:

class ApiUriBuilder implements UriBuilderInterface {
    public function build(string $endpoint, array $query = []): UriInterface {
        $base = 'https://api.example.com';
        $path = ltrim($endpoint, '/');
        $queryString = http_build_query($query);

        return UriInterface::fromString(
            "$base/$path?" . ($queryString ?? '')
        );
    }
}

Usage:

$builder = new ApiUriBuilder();
$uri = $builder->build('/users/1', ['active' => 'true']);

2. Dependency Injection for Testability

Inject UriInterface or UriBuilderInterface into services for mocking:

class UserService {
    public function __construct(
        private UriBuilderInterface $uriBuilder
    ) {}

    public function getProfileLink(int $userId): string {
        $uri = $this->uriBuilder->build("/users/$userId");
        return (string) $uri;
    }
}

Test Example:

$mockBuilder = $this->createMock(UriBuilderInterface::class);
$mockBuilder->method('build')->willReturn(UriInterface::fromString('https://mocked.com'));

$service = new UserService($mockBuilder);
$this->assertEquals('https://mocked.com', $service->getProfileLink(1));

3. Validation and Sanitization

Use UriInterface to enforce URI rules (e.g., HTTPS-only):

use Boson\UriContracts\UriInterface;

$uri = UriInterface::fromString('http://example.com');
if (str_starts_with((string) $uri, 'http://')) {
    throw new \InvalidArgumentException('URI must use HTTPS');
}

4. Integration with Laravel Routing

Generate URIs for routes using Laravel’s Url facade via an adapter:

class RouteUriAdapter implements UriInterface {
    public function __construct(private string $route) {}
    public static function fromString(string $route): self {
        return new self($route);
    }
    public function __toString(): string {
        return route($this->route);
    }
}

Usage:

$routeUri = RouteUriAdapter::fromString('users.show', ['user' => 1]);
echo (string) $routeUri; // Outputs: /users/1

5. CLI and External Service URIs

Build URIs for external APIs or webhooks:

$webhookUri = UriInterface::fromString('https://external-service.com/webhook');
$payload = [
    'url' => (string) $webhookUri,
    'event' => 'user.created'
];

Integration Tips

Laravel-Specific Patterns

  1. Service Provider Binding: Bind the UriBuilderInterface to a concrete implementation in a service provider:

    $this->app->bind(UriBuilderInterface::class, function ($app) {
        return new ApiUriBuilder();
    });
    
  2. Middleware for URI Inspection: Use UriStringable in middleware to validate or modify URIs:

    public function handle($request, Closure $next) {
        $uri = $request->getRequestUri();
        $uriObject = UriInterface::fromString($uri);
    
        if (!str_contains((string) $uriObject, 'api')) {
            abort(403, 'Unauthorized route');
        }
    
        return $next($request);
    }
    
  3. Form Request Validation: Validate URI fields in form requests:

    use Boson\UriContracts\UriInterface;
    use Illuminate\Validation\Rule;
    
    public function rules(): array {
        return [
            'callback_url' => [
                'required',
                function ($attribute, $value, $fail) {
                    $uri = UriInterface::fromString($value);
                    if (!str_starts_with((string) $uri, 'https://')) {
                        $fail('The callback URL must use HTTPS.');
                    }
                },
            ],
        ];
    }
    

Testing Patterns

  1. Mocking URIs in Unit Tests:

    $mockUri = $this->createMock(UriInterface::class);
    $mockUri->method('__toString')->willReturn('https://mocked.com');
    
    $service = new MyService($mockUri);
    
  2. Data Providers for URI Tests:

    public function uriProvider(): array {
        return [
            ['https://example.com', true],
            ['http://example.com', false],
            ['ftp://example.com', false],
        ];
    }
    
    /** @dataProvider uriProvider */
    public function testUriValidation(string $uri, bool $shouldPass): void {
        $uriObject = UriInterface::fromString($uri);
        $this->assertEquals($shouldPass, str_starts_with((string) $uriObject, 'https://'));
    }
    

Gotchas and Tips

Pitfalls

  1. Laravel’s Url Facade Overhead:

    • Directly using Laravel’s Url::to() bypasses the UriInterface abstraction. Always wrap it in an adapter if you need type safety.
    • Fix: Create a thin adapter layer (as shown in Getting Started) to avoid mixing concerns.
  2. String vs. Object URI Handling:

    • Some Laravel methods (e.g., route(), action()) return strings, not objects. You’ll need to manually convert them to UriInterface:
      $stringUri = route('users.show');
      $uriObject = UriInterface::fromString($stringUri);
      
    • Tip: Write helper methods to automate this conversion.
  3. Query String Parsing Quirks:

    • The package doesn’t include built-in query string parsing. Use PHP’s parse_str() or Symfony\Component\Uri\Uri for advanced handling.
    • Example:
      $uri = UriInterface::fromString('https://example.com?key=value');
      parse_str((string) $uri, $query);
      
  4. Relative vs. Absolute URIs:

    • The package may not handle relative URIs (e.g., /path) as expected. Test edge cases like:
      $relativeUri = UriInterface::fromString('/path');
      echo (string) $relativeUri; // Ensure this behaves as expected in your context.
      
  5. Performance with Large-Scale URI Generation:

    • If generating thousands of URIs
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky