mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Updated aspect proxy service
- Updated AspectProxyService to handle multiple handlers for each proxied object's methods. - Changed BeforeCallAspect to allow for providing a return value that should be returned to the caller instead of the proxied return value - Changed AfterCallAspect behaviour to allow for returning the value of the aspect to the caller instead of the proxied return value
This commit is contained in:
parent
b8f4576647
commit
b273f3b524
@ -22,6 +22,8 @@ interface AfterCallAspect {
|
||||
* The name of the method being called
|
||||
* @param string $args
|
||||
* The arguments that were passed to the method call
|
||||
* @param mixed $result
|
||||
* The result of calling the method on the real object
|
||||
*/
|
||||
public function afterCall($proxied, $method, $args);
|
||||
public function afterCall($proxied, $method, $args, $result);
|
||||
}
|
||||
|
@ -13,14 +13,35 @@ class AopProxyService {
|
||||
public $afterCall = array();
|
||||
|
||||
public $proxied;
|
||||
|
||||
/**
|
||||
* Because we don't know exactly how the proxied class is usually called,
|
||||
* provide a default constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public function __call($method, $args) {
|
||||
if (method_exists($this->proxied, $method)) {
|
||||
$continue = true;
|
||||
$result = null;
|
||||
|
||||
if (isset($this->beforeCall[$method])) {
|
||||
$result = $this->beforeCall[$method]->beforeCall($this->proxied, $method, $args);
|
||||
if ($result === false) {
|
||||
$continue = false;
|
||||
$methods = $this->beforeCall[$method];
|
||||
if (!is_array($methods)) {
|
||||
$methods = array($methods);
|
||||
}
|
||||
foreach ($methods as $handler) {
|
||||
$alternateReturn = null;
|
||||
$proceed = $handler->beforeCall($this->proxied, $method, $args, $alternateReturn);
|
||||
if ($proceed === false) {
|
||||
$continue = false;
|
||||
// if something is set in, use it
|
||||
if ($alternateReturn) {
|
||||
$result = $alternateReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,11 +49,20 @@ class AopProxyService {
|
||||
$result = call_user_func_array(array($this->proxied, $method), $args);
|
||||
|
||||
if (isset($this->afterCall[$method])) {
|
||||
$this->afterCall[$method]->afterCall($this->proxied, $method, $args, $result);
|
||||
$methods = $this->afterCall[$method];
|
||||
if (!is_array($methods)) {
|
||||
$methods = array($methods);
|
||||
}
|
||||
foreach ($methods as $handler) {
|
||||
$return = $handler->afterCall($this->proxied, $method, $args, $result);
|
||||
if (!is_null($return)) {
|
||||
$result = $return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ interface BeforeCallAspect {
|
||||
* The name of the method being called
|
||||
* @param string $args
|
||||
* The arguments that were passed to the method call
|
||||
* @param mixed $alternateReturn
|
||||
* An alternative return value that should be passed
|
||||
* to the caller. Only has effect of beforeCall returns false
|
||||
*/
|
||||
public function beforeCall($proxied, $method, $args);
|
||||
public function beforeCall($proxied, $method, $args, &$alternateReturn);
|
||||
}
|
||||
|
107
tests/injector/AopProxyTest.php
Normal file
107
tests/injector/AopProxyTest.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author <marcus@silverstripe.com.au>
|
||||
* @license BSD License http://www.silverstripe.org/bsd-license
|
||||
*/
|
||||
class AopProxyTest extends SapphireTest {
|
||||
public function testBeforeMethodsCalled() {
|
||||
$proxy = new AopProxyService();
|
||||
$aspect = new BeforeAfterCallTestAspect();
|
||||
$proxy->beforeCall = array(
|
||||
'myMethod' => $aspect
|
||||
);
|
||||
|
||||
$proxy->proxied = new ProxyTestObject();
|
||||
|
||||
$result = $proxy->myMethod();
|
||||
|
||||
$this->assertEquals('myMethod', $aspect->called);
|
||||
$this->assertEquals(42, $result);
|
||||
}
|
||||
|
||||
public function testBeforeMethodBlocks() {
|
||||
$proxy = new AopProxyService();
|
||||
$aspect = new BeforeAfterCallTestAspect();
|
||||
$aspect->block = true;
|
||||
|
||||
$proxy->beforeCall = array(
|
||||
'myMethod' => $aspect
|
||||
);
|
||||
|
||||
$proxy->proxied = new ProxyTestObject();
|
||||
|
||||
$result = $proxy->myMethod();
|
||||
|
||||
$this->assertEquals('myMethod', $aspect->called);
|
||||
|
||||
// the actual underlying method will NOT have been called
|
||||
$this->assertNull($result);
|
||||
|
||||
// set up an alternative return value
|
||||
$aspect->alternateReturn = 84;
|
||||
|
||||
$result = $proxy->myMethod();
|
||||
|
||||
$this->assertEquals('myMethod', $aspect->called);
|
||||
|
||||
// the actual underlying method will NOT have been called,
|
||||
// instead the alternative return value
|
||||
$this->assertEquals(84, $result);
|
||||
}
|
||||
|
||||
public function testAfterCall() {
|
||||
$proxy = new AopProxyService();
|
||||
$aspect = new BeforeAfterCallTestAspect();
|
||||
|
||||
$proxy->afterCall = array(
|
||||
'myMethod' => $aspect
|
||||
);
|
||||
|
||||
$proxy->proxied = new ProxyTestObject();
|
||||
|
||||
$aspect->modifier = function ($value) {
|
||||
return $value * 2;
|
||||
};
|
||||
|
||||
$result = $proxy->myMethod();
|
||||
$this->assertEquals(84, $result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ProxyTestObject {
|
||||
public function myMethod() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
class BeforeAfterCallTestAspect implements BeforeCallAspect, AfterCallAspect {
|
||||
public $block = false;
|
||||
|
||||
public $called;
|
||||
|
||||
public $alternateReturn;
|
||||
|
||||
public $modifier;
|
||||
|
||||
public function beforeCall($proxied, $method, $args, &$alternateReturn) {
|
||||
$this->called = $method;
|
||||
|
||||
if ($this->block) {
|
||||
if ($this->alternateReturn) {
|
||||
$alternateReturn = $this->alternateReturn;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function afterCall($proxied, $method, $args, $result) {
|
||||
if ($this->modifier) {
|
||||
$modifier = $this->modifier;
|
||||
return $modifier($result);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user