Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/ContainerWordPress/Contracts/Provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);

namespace StellarWP\Foundation\ContainerWordPress\Contracts;

use Adbar\Dot;
use StellarWP\Foundation\Container\Contracts\Providable;
use StellarWP\Foundation\ContainerWordPress\ContainerAdapter;

/**
* Base provider for WordPress projects using the WordPress-aware container.
*
* Extend this provider when a service provider needs access to WordPress-specific
* container helpers such as hook-aware provider registration.
*/
abstract class Provider implements Providable
{
/**
* Whether this service provider will be a deferred one or not.
*/
protected bool $deferred = false;

/**
* @param Dot<array-key, mixed> $config
*/
public function __construct(
/** @var Container|ContainerAdapter $container */
protected readonly Container $container,
protected readonly Dot $config
) {
}

/**
* {@inheritDoc}
*/
public function isDeferred(): bool {
return $this->deferred;
}

/**
* {@inheritDoc}
*/
public function provides(): array {
return [];
}

/**
* {@inheritDoc}
*/
public function boot(): void {
}
}
25 changes: 25 additions & 0 deletions src/ContainerWordPress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Foundation container contract:

namespace My\App;

use Adbar\Dot;
use lucatume\DI52\Container;
use StellarWP\Foundation\Container\Contracts\Container as ContainerContract;
use StellarWP\Foundation\ContainerWordPress\Contracts\Container as WPContainerContract;
Expand All @@ -35,11 +36,35 @@ $container = new ContainerAdapter(new FoundationContainerAdapter(new Container()
// Bind the concrete to the interface, so anytime we ask for a container we get this one.
$container->bind(ContainerContract::class, $container);
$container->bind(WPContainerContract::class, $container);

// Register project configuration. See the Foundation Container README for a fuller config.php example.
$container->bind(Dot::class, new Dot(require_once dirname(__FILE__) . '/config.php'));
```

Everything the [Foundation Container](https://github.com/stellarwp/foundation-container) can do,
this wrapper can do too — binding, singletons, service providers, contextual bindings, and so on.

## Service Providers

When a provider needs WordPress-specific container helpers, extend the WordPress-aware provider base:

```php
<?php declare(strict_types=1);

namespace My\App;

use StellarWP\Foundation\ContainerWordPress\Contracts\Provider;

final class My_Provider extends Provider
{
public function register(): void {
$this->container->registerOnAction( 'init', Other_Provider::class );
}
}
```

The base Foundation provider still works for providers that only need the standard container API.

## WordPress helpers

On top of the base container API, this wrapper adds hook-aware service provider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types=1);

namespace StellarWP\Foundation\Tests\Support\Fixtures\ContainerWordPress;

use StellarWP\Foundation\ContainerWordPress\Contracts\Container;
use StellarWP\Foundation\ContainerWordPress\Contracts\Provider;

/**
* Provider fixture used to verify WordPress-aware provider container typing.
*/
final class WordPressAwareProvider extends Provider
{
public const string ACTION = 'foundation_fixture_wordpress_aware_provider_ready';

public function register(): void {
$this->container->registerOnAction(self::ACTION, FirstProvider::class);
}

public function container(): Container {
return $this->container;
}
}
71 changes: 71 additions & 0 deletions tests/wpunit/ContainerWordPress/ProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php declare(strict_types=1);

namespace StellarWP\Foundation\Tests\WPUnit\ContainerWordPress;

use Adbar\Dot;
use lucatume\DI52\Container as DI52Container;
use StellarWP\Foundation\Container\ContainerAdapter as FoundationContainerAdapter;
use StellarWP\Foundation\Container\Contracts\Container as FoundationContainer;
use StellarWP\Foundation\Container\Contracts\Providable;
use StellarWP\Foundation\ContainerWordPress\ContainerAdapter;
use StellarWP\Foundation\ContainerWordPress\Contracts\Container as WPContainerContract;
use StellarWP\Foundation\Tests\Support\Fixtures\ContainerWordPress\FirstProvider;
use StellarWP\Foundation\Tests\Support\Fixtures\ContainerWordPress\WordPressAwareProvider;
use StellarWP\Foundation\Tests\WPUnitSupport\WPTestCase;

final class ProviderTest extends WPTestCase
{
private ContainerAdapter $adapter;

protected function setUp(): void {
parent::setUp();

$this->adapter = new ContainerAdapter(new FoundationContainerAdapter(new DI52Container()));

$this->adapter->bind(FoundationContainer::class, $this->adapter);
$this->adapter->bind(WPContainerContract::class, $this->adapter);
$this->adapter->singleton(Dot::class, new Dot());
}

/**
* Build the "registered" action name the adapter fires for a provider or alias.
*/
private function registered_action(string $identifier): string {
return 'nexcess/foundation/container/wp/' . $identifier . '/registered';
}

/**
* Count how many times a WordPress action fires while a callback is attached.
*/
private function count_action(string $action): callable {
$original = did_action($action);

return static fn (): int => did_action($action) - $original;
}

public function test_it_is_a_providable_provider_with_a_wordpress_container(): void {
$provider = $this->adapter->get(WordPressAwareProvider::class);

$this->assertInstanceOf(Providable::class, $provider);
$this->assertInstanceOf(WordPressAwareProvider::class, $provider);
$this->assertSame($this->adapter, $provider->container());
$this->assertFalse($provider->isDeferred());
$this->assertSame([], $provider->provides());
}

public function test_it_allows_subclasses_to_use_wordpress_container_methods(): void {
$fired = $this->count_action($this->registered_action(FirstProvider::class));

$this->adapter->register(WordPressAwareProvider::class);

$this->assertSame(0, $fired());

do_action(WordPressAwareProvider::ACTION);

$this->assertSame(1, $fired());

do_action(WordPressAwareProvider::ACTION);

$this->assertSame(1, $fired());
}
}
Loading