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

Utils Laravel Package

middlewares/utils

Common utilities for Middlewares PSR packages: auto-discovered PSR-7/PSR-17 Factory (Diactoros, Guzzle, Slim, Nyholm, Sunrise) plus PSR-15 Dispatcher for testing, callable handler helpers, and HTTP error exceptions.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require middlewares/utils
    

    No additional configuration is required for basic usage.

  2. First Use Case: Create a PSR-7 request/response in a Laravel controller or middleware:

    use Middlewares\Utils\Factory;
    
    // Create a request
    $request = Factory::createRequest('GET', '/api/users');
    
    // Create a response
    $response = Factory::createResponse(200)
        ->withHeader('Content-Type', 'application/json')
        ->withBody(Factory::createStream(json_encode(['users' => []])));
    
  3. Where to Look First:

    • Factory: For PSR-7/PSR-17 instance creation.
    • Dispatcher: For testing middleware stacks.
    • CallableHandler: For converting callables into middleware.
    • HttpErrorException: For HTTP error handling.

Implementation Patterns

1. PSR-7/PSR-17 Instance Creation

  • Pattern: Use Factory for all PSR-7/PSR-17 objects (requests, responses, streams, etc.).
  • Example:
    // In a Laravel middleware or service
    public function handle($request, Closure $next) {
        $response = Factory::createResponse(200)
            ->withBody(Factory::createStream('Hello, Laravel!'));
    
        return $next($request)->withHeader('X-Custom', 'Value');
    }
    
  • Integration Tip: Override the default factory in bootstrap/app.php:
    use Middlewares\Utils\Factory;
    use Middlewares\Utils\FactoryDiscovery;
    
    Factory::setFactory(new FactoryDiscovery(
        'Laravel\Psr17Factories', // Custom factory class
        FactoryDiscovery::SLIM,
        FactoryDiscovery::GUZZLE
    ));
    

2. Middleware Testing

  • Pattern: Use Dispatcher to test middleware stacks in isolation.
  • Example:
    use Middlewares\Utils\Dispatcher;
    use App\Http\Middleware\Authenticate;
    
    $middlewareStack = [
        new Authenticate(),
        function ($request, $next) {
            return $next($request)->withHeader('X-Test', 'Passed');
        }
    ];
    
    $response = Dispatcher::run($middlewareStack, Factory::createRequest('GET', '/'));
    $this->assertEquals('Passed', $response->getHeaderLine('X-Test'));
    
  • Integration Tip: Use in Laravel's phpunit.xml for middleware tests:
    <env name="PSR_HTTP_FACTORY" value="Middlewares\Utils\Factory"/>
    

3. Callable Middleware

  • Pattern: Convert anonymous functions or closures into middleware using CallableHandler.
  • Example:
    use Middlewares\Utils\CallableHandler;
    
    $middleware = new CallableHandler(function ($request, $next) {
        return $next($request)->withHeader('X-Processed', 'true');
    });
    
    // Register in Laravel's kernel
    $this->app->middleware($middleware);
    
  • Integration Tip: Use for one-off middleware in routes:
    Route::get('/test', function () {
        return response()->json(['status' => 'ok']);
    })->middleware(new CallableHandler(function ($request, $next) {
        // Pre-processing logic
        return $next($request);
    }));
    

4. HTTP Error Handling

  • Pattern: Use HttpErrorException for consistent error responses.
  • Example:
    use Middlewares\Utils\HttpErrorException;
    
    try {
        if (!$user) {
            throw HttpErrorException::create(404, ['error' => 'User not found']);
        }
    } catch (HttpErrorException $e) {
        return response()->json($e->getContext(), $e->getCode());
    }
    
  • Integration Tip: Create a global exception handler in Laravel:
    public function render($request, Throwable $exception) {
        if ($exception instanceof HttpErrorException) {
            return response()->json($exception->getContext(), $exception->getCode());
        }
        return parent::render($request, $exception);
    }
    

5. Dependency Injection

  • Pattern: Bind factories to Laravel's container for reuse.
  • Example:
    $this->app->bind(\Psr\Http\Message\ResponseFactoryInterface::class, function () {
        return Factory::getResponseFactory();
    });
    
  • Integration Tip: Use in service providers to inject PSR-17 factories:
    public function register() {
        $this->app->singleton(\Psr\Http\Message\RequestFactoryInterface::class, function () {
            return Factory::getRequestFactory();
        });
    }
    

Gotchas and Tips

1. Factory Detection Order

  • Gotcha: The FactoryDiscovery class prioritizes libraries in this order: Slim > Guzzle > Diactoros > Nyholm > Sunrise. If you need a specific library (e.g., Diactoros), explicitly set it:
    Factory::setFactory(new FactoryDiscovery(
        FactoryDiscovery::DIACTOROS,
        FactoryDiscovery::GUZZLE
    ));
    
  • Tip: Use Factory::getFactory() to inspect the current factory instance.

2. PHP Version Compatibility

  • Gotcha: The package requires PHP 8.1+. Older versions will fail. Check for deprecation warnings (e.g., PHP 8.4's implicitly nullable parameters).
  • Tip: Use php -v to verify compatibility before upgrading.

3. CallableHandler Quirks

  • Gotcha: The callable must return:
    • A Psr\Http\Message\ResponseInterface,
    • null or a scalar,
    • An object with __toString(). Otherwise, it throws UnexpectedValueException.
  • Tip: Validate return types in CI/CD:
    $callable = new CallableHandler(function () {
        return 'valid'; // Scalar is allowed
    });
    

4. Dispatcher Limitations

  • Gotcha: The Dispatcher does not support PSR-11 containers (e.g., Laravel's Illuminate\Container\Container). Use CallableHandler or Laravel's built-in middleware resolution for DI.
  • Tip: For Laravel, use the handle() method directly:
    $middleware = new \App\Http\Middleware\Authenticate($this->app['request']);
    $response = $middleware->handle($request, function () {
        return Factory::createResponse(200);
    });
    

5. Stream Handling

  • Gotcha: Streams created via Factory::createStream() are not seekable by default. Use Laminas\Diactoros\Stream for seekable streams:
    $stream = new \Laminas\Diactoros\Stream('php://memory', 'r+');
    $uploadedFile = Factory::createUploadedFile($stream);
    
  • Tip: Wrap streams in Laravel's Illuminate\Http\File for uploads:
    $file = new \Illuminate\Http\File($uploadedFile->getStream(), $uploadedFile->getClientFilename());
    

6. Laravel-Specific Tips

  • Tip: Override Laravel's default factories in AppServiceProvider:
    public function boot() {
        \Middlewares\Utils\Factory::setFactory(new \Laravel\Psr17Factories());
    }
    
  • Tip: Use Factory in Laravel's Http\Middleware:
    public function handle($request, Closure $next) {
        $response = $next($request);
        return Factory::getResponseFactory()->createResponse()
            ->withHeader('X-Cache', 'Miss');
    }
    

7. Debugging

  • Tip: Enable PSR-17 factory logging:

    \Middlewares\Utils\Factory::getFactory()->setResponseFactory(
        new \Laminas\Diactoros\ResponseFactory()
    );
    

    Check logs for factory initialization errors.

  • Tip: Use var_dump(Factory::getFactory()) to debug factory configuration.

8. Extending the Package

  • Extension Point: Implement Psr\Http\Factory\FactoryInterface for custom factories:

    class CustomFactory implements \Psr\Http\Factory\FactoryInterface {
        public function createRequest(string $method, $uri, array $serverParams = []): \Psr\Http\Message\RequestInterface {
            // Custom logic
        }
        // ... other methods
    }
    

    Register it via Factory::setFactory(new CustomFactory()).

  • Extension Point: Subclass HttpErrorException for custom error contexts:

    class
    
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