Some small imrpovements in the dependency injection framework:
- camelCase methods changed to snake_case for consistency with WP. - Added a check in `ExtendedContainer::get` that throws an informative exception if a non-namespaced class name is passed. - `container->reset_resolved()` is called during unit testing bootstrap. - Added some utility methods in `WC_Unit_Test_Case`.
This commit is contained in:
parent
d5d02a7175
commit
d55f7d10f8
|
@ -17,8 +17,8 @@ use League\Container\Definition\Definition;
|
|||
* See the documentation of the original class this one is based on (https://container.thephpleague.com/3.x/service-providers)
|
||||
* for basic usage details. What this class adds is:
|
||||
*
|
||||
* - The `addWithAutoArguments` method that allows to register classes without having to specify the constructor arguments.
|
||||
* - The `shareWithAutoArguments` method, sibling of the above.
|
||||
* - The `add_with_auto_arguments` method that allows to register classes without having to specify the constructor arguments.
|
||||
* - The `share_with_auto_arguments` method, sibling of the above.
|
||||
* - Convenience `add` and `share` methods that are just proxies for the same methods in `$this->getContainer()`.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Tools\DependencyManagement
|
||||
|
@ -38,7 +38,7 @@ abstract class AbstractServiceProvider extends \League\Container\ServiceProvider
|
|||
*
|
||||
* @throws \Exception Error when reflecting the class, or class constructor is not public, or an argument has no valid type hint.
|
||||
*/
|
||||
public function addWithAutoArguments( string $class_name, $concrete = null, bool $shared = false ) : DefinitionInterface {
|
||||
public function add_with_auto_arguments( string $class_name, $concrete = null, bool $shared = false ) : DefinitionInterface {
|
||||
try {
|
||||
$reflector = new \ReflectionClass( $class_name );
|
||||
} catch ( \ReflectionException $ex ) {
|
||||
|
@ -90,8 +90,8 @@ abstract class AbstractServiceProvider extends \League\Container\ServiceProvider
|
|||
*
|
||||
* @throws \Exception Error when reflecting the class, or class constructor is not public, or an argument has no valid type hint.
|
||||
*/
|
||||
public function shareWithAutoArguments( string $class_name, $concrete = null ) : DefinitionInterface {
|
||||
return $this->addWithAutoArguments( $class_name, $concrete, true );
|
||||
public function share_with_auto_arguments( string $class_name, $concrete = null ) : DefinitionInterface {
|
||||
return $this->add_with_auto_arguments( $class_name, $concrete, true );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,7 @@ class ExtendedContainer extends \League\Container\Container {
|
|||
* @throws \Exception Invalid parameters.
|
||||
*/
|
||||
public function add( string $id, $concrete = null, bool $shared = null ) : DefinitionInterface {
|
||||
if ( ! $this->class_is_in_root_namespace( $id ) && ! in_array( $id, $this->registration_whitelist ) ) {
|
||||
if ( ! $this->class_is_in_root_namespace( $id ) && ! in_array( $id, $this->registration_whitelist, true ) ) {
|
||||
throw new \Exception( "Can't use the container to register '$id', only objects in the " . Container::WOOCOMMERCE_ROOT_NAMESPACE . ' namespace are allowed for registration.' );
|
||||
}
|
||||
|
||||
|
@ -82,4 +82,21 @@ class ExtendedContainer extends \League\Container\Container {
|
|||
$definition->setConcrete( $concrete );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of a registered class.
|
||||
*
|
||||
* @param string $id The class name.
|
||||
* @param bool $new True to generate a new instance even if the class was registered as shared.
|
||||
*
|
||||
* @return object An instance of the requested class.
|
||||
* @throws \Exception Attempt to get an instance of a non-namespaced class.
|
||||
*/
|
||||
public function get( $id, bool $new = false ) {
|
||||
if ( false === strpos( $id, '\\' ) ) {
|
||||
throw new \Exception( "Attempt to get an instance of the non-namespaced class '$id' from the container, did you forget to add a namespace import?" );
|
||||
}
|
||||
|
||||
return parent::get( $id, $new );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,6 @@ class ProxiesServiceProvider extends AbstractServiceProvider {
|
|||
*/
|
||||
public function register() {
|
||||
$this->share( ActionsProxy::class );
|
||||
$this->shareWithAutoArguments( LegacyProxy::class );
|
||||
$this->share_with_auto_arguments( LegacyProxy::class );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class ActionsProxy {
|
|||
*
|
||||
* @return int The number of times action hook $tag is fired.
|
||||
*/
|
||||
public function didAction( $tag ) {
|
||||
public function did_action( $tag ) {
|
||||
return did_action( $tag );
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class ActionsProxy {
|
|||
*
|
||||
* @return mixed The filtered value after all hooked functions are applied to it.
|
||||
*/
|
||||
public function applyFilters( $tag, $value, ...$parameters ) {
|
||||
public function apply_filters( $tag, $value, ...$parameters ) {
|
||||
return apply_filters( $tag, $value, ...$parameters );
|
||||
}
|
||||
|
||||
|
|
|
@ -22,22 +22,6 @@ use \Psr\Container\ContainerInterface as Container;
|
|||
*/
|
||||
class LegacyProxy {
|
||||
|
||||
/**
|
||||
* Holds the instance of the container to use.
|
||||
*
|
||||
* @var Container
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the class.
|
||||
*
|
||||
* @param Container $container The container to use.
|
||||
*/
|
||||
public function __construct( Container $container ) {
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of a given legacy class.
|
||||
* This must not be used to get instances of classes in the `src` directory.
|
||||
|
@ -47,14 +31,14 @@ class LegacyProxy {
|
|||
* @return object The instance of the class.
|
||||
* @throws \Exception The requested class belongs to the `src` directory, or there was an error creating an instance of the class.
|
||||
*/
|
||||
public function getInstanceOf( string $class_name ) {
|
||||
if ( $this->container->has( $class_name ) ) {
|
||||
public function get_instance_of( string $class_name ) {
|
||||
if ( false !== strpos( $class_name, '\\' ) ) {
|
||||
throw new \Exception( 'The LegacyProxy class is not intended for getting instances of classes in the src directory, please use constructor injection or the instance of \\Psr\\Container\\ContainerInterface for that.' );
|
||||
}
|
||||
|
||||
try {
|
||||
// If a class has a special procedure to obtain a instance, use it.
|
||||
$instance = $this->getSpecialInstanceOf( $class_name );
|
||||
$instance = $this->get_special_instance_of( $class_name );
|
||||
if ( ! is_null( $instance ) ) {
|
||||
return $instance;
|
||||
}
|
||||
|
@ -78,7 +62,7 @@ class LegacyProxy {
|
|||
*
|
||||
* @return object|null The instance, or null if there's no special procedure for that class.
|
||||
*/
|
||||
private function getSpecialInstanceOf( string $class_name ) {
|
||||
private function get_special_instance_of( string $class_name ) {
|
||||
if ( \WC_Queue_Interface::class === $class_name ) {
|
||||
return \WC_Queue::instance();
|
||||
}
|
||||
|
@ -95,7 +79,7 @@ class LegacyProxy {
|
|||
*
|
||||
* @return mixed The result from the function.
|
||||
*/
|
||||
public function callFunction( $function_name, ...$parameters ) {
|
||||
public function call_function( $function_name, ...$parameters ) {
|
||||
return call_user_func_array( $function_name, $parameters );
|
||||
}
|
||||
|
||||
|
@ -109,7 +93,7 @@ class LegacyProxy {
|
|||
*
|
||||
* @return mixed The result from the method.
|
||||
*/
|
||||
public function callStatic( $class_name, $method_name, ...$parameters ) {
|
||||
public function call_static( $class_name, $method_name, ...$parameters ) {
|
||||
return call_user_func_array( "$class_name::$method_name", $parameters );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,12 +118,12 @@ class MockableLegacyProxy extends \Automattic\WooCommerce\Proxies\LegacyProxy {
|
|||
*
|
||||
* @return mixed The result from the function or mock callback.
|
||||
*/
|
||||
public function callFunction( $function_name, ...$parameters ) {
|
||||
public function call_function( $function_name, ...$parameters ) {
|
||||
if ( array_key_exists( $function_name, $this->mocked_functions ) ) {
|
||||
return call_user_func_array( $this->mocked_functions[ $function_name ], $parameters );
|
||||
}
|
||||
|
||||
return parent::callFunction( $function_name, ...$parameters );
|
||||
return parent::call_function( $function_name, ...$parameters );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,7 +139,7 @@ class MockableLegacyProxy extends \Automattic\WooCommerce\Proxies\LegacyProxy {
|
|||
*
|
||||
* @return mixed The result from the method or mock callback.
|
||||
*/
|
||||
public function callStatic( $class_name, $method_name, ...$parameters ) {
|
||||
public function call_static( $class_name, $method_name, ...$parameters ) {
|
||||
if ( array_key_exists( $class_name, $this->mocked_statics ) ) {
|
||||
$class_mocks = $this->mocked_statics[ $class_name ];
|
||||
if ( array_key_exists( $method_name, $class_mocks ) ) {
|
||||
|
@ -148,7 +148,7 @@ class MockableLegacyProxy extends \Automattic\WooCommerce\Proxies\LegacyProxy {
|
|||
}
|
||||
}
|
||||
|
||||
return parent::callStatic( $class_name, $method_name, ...$parameters );
|
||||
return parent::call_static( $class_name, $method_name, ...$parameters );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,12 +163,12 @@ class MockableLegacyProxy extends \Automattic\WooCommerce\Proxies\LegacyProxy {
|
|||
* @return object The (possibly mocked) instance of the class.
|
||||
* @throws \Exception The requested class belongs to the `src` directory, or there was an error creating an instance of the class.
|
||||
*/
|
||||
public function getInstanceOf( string $class_name ) {
|
||||
public function get_instance_of( string $class_name ) {
|
||||
if ( array_key_exists( $class_name, $this->mocked_classes ) ) {
|
||||
$mock = $this->mocked_classes[ $class_name ];
|
||||
return is_callable( $mock ) ? call_user_func( $mock, $class_name ) : $mock;
|
||||
}
|
||||
|
||||
return parent::getInstanceOf( $class_name );
|
||||
return parent::get_instance_of( $class_name );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use Automattic\WooCommerce\Testing\Tools\CodeHacking\CodeHacker;
|
|||
use Automattic\WooCommerce\Testing\Tools\CodeHacking\Hacks\StaticMockerHack;
|
||||
use Automattic\WooCommerce\Testing\Tools\CodeHacking\Hacks\FunctionsMockerHack;
|
||||
use Automattic\WooCommerce\Testing\Tools\CodeHacking\Hacks\BypassFinalsHack;
|
||||
|
||||
use Automattic\WooCommerce\Testing\Tools\DependencyManagement\MockableLegacyProxy;
|
||||
|
||||
/**
|
||||
|
@ -127,6 +126,7 @@ class WC_Unit_Tests_Bootstrap {
|
|||
$inner_container = $inner_container_property->getValue( wc_get_container() );
|
||||
|
||||
$inner_container->replace( LegacyProxy::class, MockableLegacyProxy::class );
|
||||
$inner_container->reset_resolved();
|
||||
|
||||
$GLOBALS['wc_container'] = $inner_container;
|
||||
}
|
||||
|
|
|
@ -152,6 +152,31 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of a class that has been registered in the dependency injection container.
|
||||
* To get an instance of a legacy class (such as the ones in the 'íncludes' directory) use
|
||||
* 'get_legacy_instance_of' instead.
|
||||
*
|
||||
* @param string $class_name The class name to get an instance of.
|
||||
*
|
||||
* @return mixed The instance.
|
||||
*/
|
||||
public function get_instance_of( string $class_name ) {
|
||||
return wc_get_container()->get( $class_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of legacy class (such as the ones in the 'íncludes' directory).
|
||||
* To get an instance of a class registered in the dependency injection container use 'get_instance_of' instead.
|
||||
*
|
||||
* @param string $class_name The class name to get an instance of.
|
||||
*
|
||||
* @return mixed The instance.
|
||||
*/
|
||||
public function get_legacy_instance_of( string $class_name ) {
|
||||
return wc_get_container()->get( LegacyProxy::class )->get_instance_of( $class_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all the cached resolutions in the dependency injection container, so any further "get"
|
||||
* for shared definitions will generate the instance again.
|
||||
|
@ -161,6 +186,13 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
|
|||
wc_get_container()->reset_resolved();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the mock legacy proxy class so that all the registered mocks are unregistered.
|
||||
*/
|
||||
public function reset_legacy_proxy_mocks() {
|
||||
wc_get_container()->get( LegacyProxy::class )->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the function mocks to use in the mockable LegacyProxy.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue