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

Ringphp Laravel Package

ezimuel/ringphp

RingPHP provides a lightweight, PSR-7–focused abstraction for HTTP clients and servers, inspired by the Ring specification. Compose middleware-style handlers, adapt to popular transports, and build reusable, testable HTTP stacks without locking into a single client.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require ezimuel/ringphp
    
    • No additional configuration is required for basic usage.
  2. First Use Case: Wrapping a Request RingPHP is primarily used to wrap HTTP requests (e.g., for testing or middleware injection). Start with a simple example:

    use Ezimuel\RingPHP\Ring;
    use GuzzleHttp\Psr7\Request;
    
    $request = new Request('GET', 'https://example.com/api');
    $response = Ring::run($request, function ($request) {
        // Modify or inspect the request here (e.g., add headers)
        $request = $request->withHeader('X-Custom-Header', 'value');
        return $request;
    });
    
    • Key Files to Explore:
      • src/Ring.php (core logic)
      • src/Response.php (response handling)

Implementation Patterns

1. Middleware Injection

RingPHP excels at stackable middleware—ideal for testing or modifying requests/responses in Elasticsearch clients (e.g., elasticsearch/elasticsearch). Example: Logging Middleware

use Ezimuel\RingPHP\Ring;
use Psr\Http\Message\RequestInterface;

$middleware = function (callable $next) {
    return function (RequestInterface $request) use ($next) {
        logger()->info('Request:', ['method' => $request->getMethod(), 'uri' => (string)$request->getUri()]);
        return $next($request);
    };
};

$response = Ring::run($request, $middleware);

2. Mocking HTTP Calls for Testing

Replace real HTTP clients (e.g., Guzzle) with RingPHP in unit tests:

public function testSearchQuery()
{
    $mockResponse = new Response(200, [], json_encode(['hits' => []]));
    $request = new Request('GET', '/search');

    $response = Ring::run($request, function ($req) use ($mockResponse) {
        return $mockResponse; // Short-circuit to return mock
    });

    $this->assertEquals(200, $response->getStatusCode());
}

3. Integration with Elasticsearch-PHP

Use RingPHP to intercept and modify Elasticsearch requests:

use Elasticsearch\ClientBuilder;

$client = ClientBuilder::create()
    ->setHosts(['http://localhost:9200'])
    ->setHandler(Ring::createHandler(function ($request) {
        // Add auth token to every request
        return $request->withHeader('Authorization', 'Bearer token');
    }))
    ->build();

4. Response Transformation

Modify responses before they reach the application:

$response = Ring::run($request, function ($req) {
    return Ring::run($req, function ($req) {
        // First middleware (e.g., auth)
        return $req;
    }, function ($res) {
        // Second middleware: transform response
        $data = json_decode($res->getBody(), true);
        return new Response($res->getStatusCode(), [], json_encode(['transformed' => $data]));
    });
});

Gotchas and Tips

Pitfalls

  1. No PSR-15 Middleware Support

    • RingPHP uses anonymous functions (not PSR-15 MiddlewareInterface). Avoid mixing with frameworks like Lumen/Laravel that expect PSR-15.
    • Workaround: Wrap PSR-15 middleware in a Ring-compatible closure.
  2. Response Handling Quirks

    • RingPHP’s run() expects the final middleware to return a Response or StreamInterface. Forgetting this causes RuntimeExceptions.
    • Debug Tip: Check the stack trace for InvalidArgumentException if responses are malformed.
  3. Elasticsearch-PHP Specifics

    • When using with elasticsearch/elasticsearch, ensure the handler stack is properly configured. Misconfigured handlers may silently fail.
    • Tip: Use ClientBuilder::setHandlerStack() to debug:
      $client->getHandlerStack()->push(Ring::createHandler(...));
      
  4. Performance Overhead

    • Each middleware adds a closure call. For high-throughput apps (e.g., bulk Elasticsearch ops), benchmark middleware count.
  5. PHP 8.5 Compatibility

    • Fixed in 1.4.1: The package now properly handles curl_close() calls in PHP 8.5 environments, avoiding potential deprecation warnings or errors.
    • Note: If you encounter issues with curl_close() in custom middleware, ensure your code is compatible with PHP 8.5’s stricter handling of cURL resources.

Debugging Tips

  • Log Middleware Output:
    Ring::run($request, function ($req) {
        logger()->debug('Request:', (string)$req);
        return $req;
    });
    
  • Inspect the Handler Stack:
    $handler = Ring::createHandler(...);
    $handler->__invoke($request); // Manually trigger to debug
    

Extension Points

  1. Custom Response Classes Extend Ezimuel\RingPHP\Response to add domain-specific logic:

    class ElasticResponse extends Response {
        public function getHits() { /* ... */ }
    }
    
  2. Async Support (Experimental) RingPHP is synchronous, but you can wrap async logic in middleware:

    $middleware = function ($next) {
        return function ($req) use ($next) {
            return \React\Promise\resolve($next($req));
        };
    };
    
  3. Integration with Laravel Use Ring::run() in service providers to wrap HTTP clients:

    $this->app->singleton('elasticsearch', function () {
        return ClientBuilder::create()
            ->setHandler(Ring::createHandler($this->app['middleware.elasticsearch']))
            ->build();
    });
    
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.
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon