<?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Internal\DependencyManagement;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Conditional;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\League\Container\Definition\DefinitionInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\League\Container\ServiceProvider\AbstractServiceProvider as LeagueProvider;
/**
* Class AbstractServiceProvider
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Internal\DependencyManagement
*/
abstract class AbstractServiceProvider extends LeagueProvider {
/**
* Array of classes provided by this container.
*
* Keys should be the class name, and the value can be anything (like `true`).
*
* @var array
*/
protected $provides = [];
/**
* Returns a boolean if checking whether this provider provides a specific
* service or returns an array of provided services if no argument passed.
*
* @param string $service
*
* @return boolean
*/
public function provides( string $service ): bool {
return array_key_exists( $service, $this->provides );
}
/**
* Use the register method to register items with the container via the
* protected $this->container property or the `getContainer` method
* from the ContainerAwareTrait.
*
* @return void
*/
public function register(): void {
foreach ( $this->provides as $class => $provided ) {
$this->share( $class );
}
}
/**
* Add an interface to the container.
*
* @param string $interface_name The interface to add.
* @param string|null $concrete (Optional) The concrete class.
*
* @return DefinitionInterface
*/
protected function share_concrete( string $interface_name, $concrete = null ): DefinitionInterface {
return $this->getContainer()->addShared( $interface_name, $concrete );
}
/**
* Share a class and add interfaces as tags.
*
* @param string $class_name The class name to add.
* @param mixed ...$arguments Constructor arguments for the class.
*
* @return DefinitionInterface
*/
protected function share_with_tags( string $class_name, ...$arguments ): DefinitionInterface {
$definition = $this->share( $class_name, ...$arguments );
foreach ( class_implements( $class_name ) as $interface_name ) {
$definition->addTag( $interface_name );
}
return $definition;
}
/**
* Share a class.
*
* Shared classes will always return the same instance of the class when the class is requested
* from the container.
*
* @param string $class_name The class name to add.
* @param mixed ...$arguments Constructor arguments for the class.
*
* @return DefinitionInterface
*/
protected function share( string $class_name, ...$arguments ): DefinitionInterface {
return $this->getContainer()->addShared( $class_name )->addArguments( $arguments );
}
/**
* Add a class.
*
* Classes will return a new instance of the class when the class is requested from the container.
*
* @param string $class_name The class name to add.
* @param mixed ...$arguments Constructor arguments for the class.
*
* @return DefinitionInterface
*/
protected function add( string $class_name, ...$arguments ): DefinitionInterface {
return $this->getContainer()->add( $class_name )->addArguments( $arguments );
}
/**
* Maybe share a class and add interfaces as tags.
*
* This will also check any classes that implement the Conditional interface and only add them if
* they are needed.
*
* @param string $class_name The class name to add.
* @param mixed ...$arguments Constructor arguments for the class.
*/
protected function conditionally_share_with_tags( string $class_name, ...$arguments ) {
$implements = class_implements( $class_name );
if ( array_key_exists( Conditional::class, $implements ) ) {
/** @var Conditional $class */
if ( ! $class_name::is_needed() ) {
return;
}
}
$this->provides[ $class_name ] = true;
$this->share_with_tags( $class_name, ...$arguments );
}
}