Skip to content

Instantly share code, notes, and snippets.

@dg
Last active December 10, 2024 00:04
Show Gist options
  • Save dg/7f02403bd36d9d1c73802a6268a4361f to your computer and use it in GitHub Desktop.
Save dg/7f02403bd36d9d1c73802a6268a4361f to your computer and use it in GitHub Desktop.
PSR-11 adapter for Nette DI Container
<?php
declare(strict_types=1);
use Nette\DI\Container;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
// ↓ For the sake of this example, I'm implementing these two ↓
// ↓ Exceptions here, but they should be in their own namespace, ↓
// ↓ as should Psr11ContainerAdapter for that matter: ↓
class Psr11ContainerException extends Exception implements ContainerExceptionInterface
{
}
class Psr11NotFoundException extends Psr11ContainerException implements NotFoundExceptionInterface
{
}
class Psr11ContainerAdapter implements ContainerInterface
{
public function __construct(
private Container $netteContainer
) {
}
public function get($id)
{
try {
return $this->netteContainer->getService($id);
} catch (Nette\DI\MissingServiceException $e) {
throw new Psr11NotFoundException("Service not found: {$id}", previous: $e);
} catch (Throwable $e) {
throw new Psr11ContainerException("Failed to resolve service: {$id}", previous: $e);
}
}
public function has($id)
{
return $this->netteContainer->hasService($id);
}
}
// usage:
// $psr11Adapter = new Psr11ContainerAdapter($netteContainer);
@michkozak
Copy link

michkozak commented Dec 7, 2024

Hey David, just wanted to let you know that this PSR-11 adapter is not correct.

First: in your get($id) implementation, you're throwing a Psr\Container\NotFoundException. There's no Psr\Container\NotFoundException in PSR-11, there's only a Psr\Container\NotFoundExceptionInterface interface which — being an interface — cannot be instantiated and thrown. You have to create an exception that implements it — and throw that.

Second: get($id) has to throw an exception implementing Psr\Container\ContainerExceptionInterface interface if resolving $id fails (for whatever reason) — this adapter is not doing that at all. You have to wrap return $this->netteContainer->getService($id); in a try...catch block to catch any thrown exception and if that happens — throw an exception implementing Psr\Container\ContainerExceptionInterface interface.

It should look something like this:

<?php

declare(strict_types=1);

use Psr\Container\ContainerInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Nette\DI\Container;

// ↓ For the sake of this example, I'm implementing these two    ↓
// ↓ Exceptions here, but they should be in their own namespace, ↓
// ↓ as should Psr11ContainerAdapter for that matter:            ↓
class Psr11ContainerException extends Exception implements ContainerExceptionInterface {}
class Psr11NotFoundException extends Psr11ContainerException implements NotFoundExceptionInterface {}

class Psr11ContainerAdapter implements ContainerInterface
{
    public function __construct(private Container $netteContainer) 
    {
        //
    }

    public function get($id)
    {
        if ( ! $this->netteContainer->hasService($id)) {
            throw new Psr11NotFoundException("Service not found: {$id}");
        }

        try {
            return $this->netteContainer->getService($id);
        } catch (Throwable $th) {
            throw new Psr11ContainerException("Failed to resolve service: {$id}", previous: $th); 
        }
    }

    public function has($id)
    {
        return $this->netteContainer->hasService($id);
    }
}


// usage:
// $psr11Adapter = new Psr11ContainerAdapter($netteContainer);

@dg
Copy link
Author

dg commented Dec 10, 2024

@michkozak thanks, I updated the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment