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
|
* The name of the method being called
|
||||||
* @param string $args
|
* @param string $args
|
||||||
* The arguments that were passed to the method call
|
* 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);
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,34 @@ class AopProxyService {
|
|||||||
|
|
||||||
public $proxied;
|
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) {
|
public function __call($method, $args) {
|
||||||
if (method_exists($this->proxied, $method)) {
|
if (method_exists($this->proxied, $method)) {
|
||||||
$continue = true;
|
$continue = true;
|
||||||
|
$result = null;
|
||||||
|
|
||||||
if (isset($this->beforeCall[$method])) {
|
if (isset($this->beforeCall[$method])) {
|
||||||
$result = $this->beforeCall[$method]->beforeCall($this->proxied, $method, $args);
|
$methods = $this->beforeCall[$method];
|
||||||
if ($result === false) {
|
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;
|
$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);
|
$result = call_user_func_array(array($this->proxied, $method), $args);
|
||||||
|
|
||||||
if (isset($this->afterCall[$method])) {
|
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
|
* The name of the method being called
|
||||||
* @param string $args
|
* @param string $args
|
||||||
* The arguments that were passed to the method call
|
* 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