CallCenter.php (4973B)
1 <?php 2 3 /* 4 * This file is part of the Prophecy. 5 * (c) Konstantin Kudryashov <ever.zet@gmail.com> 6 * Marcello Duarte <marcello.duarte@gmail.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Prophecy\Call; 13 14 use Prophecy\Prophecy\MethodProphecy; 15 use Prophecy\Prophecy\ObjectProphecy; 16 use Prophecy\Argument\ArgumentsWildcard; 17 use Prophecy\Util\StringUtil; 18 use Prophecy\Exception\Call\UnexpectedCallException; 19 20 /** 21 * Calls receiver & manager. 22 * 23 * @author Konstantin Kudryashov <ever.zet@gmail.com> 24 */ 25 class CallCenter 26 { 27 private $util; 28 29 /** 30 * @var Call[] 31 */ 32 private $recordedCalls = array(); 33 34 /** 35 * Initializes call center. 36 * 37 * @param StringUtil $util 38 */ 39 public function __construct(StringUtil $util = null) 40 { 41 $this->util = $util ?: new StringUtil; 42 } 43 44 /** 45 * Makes and records specific method call for object prophecy. 46 * 47 * @param ObjectProphecy $prophecy 48 * @param string $methodName 49 * @param array $arguments 50 * 51 * @return mixed Returns null if no promise for prophecy found or promise return value. 52 * 53 * @throws \Prophecy\Exception\Call\UnexpectedCallException If no appropriate method prophecy found 54 */ 55 public function makeCall(ObjectProphecy $prophecy, $methodName, array $arguments) 56 { 57 $backtrace = debug_backtrace(); 58 59 $file = $line = null; 60 if (isset($backtrace[2]) && isset($backtrace[2]['file'])) { 61 $file = $backtrace[2]['file']; 62 $line = $backtrace[2]['line']; 63 } 64 65 // If no method prophecies defined, then it's a dummy, so we'll just return null 66 if ('__destruct' === $methodName || 0 == count($prophecy->getMethodProphecies())) { 67 $this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line); 68 69 return null; 70 } 71 72 // There are method prophecies, so it's a fake/stub. Searching prophecy for this call 73 $matches = array(); 74 foreach ($prophecy->getMethodProphecies($methodName) as $methodProphecy) { 75 if (0 < $score = $methodProphecy->getArgumentsWildcard()->scoreArguments($arguments)) { 76 $matches[] = array($score, $methodProphecy); 77 } 78 } 79 80 // If fake/stub doesn't have method prophecy for this call - throw exception 81 if (!count($matches)) { 82 throw $this->createUnexpectedCallException($prophecy, $methodName, $arguments); 83 } 84 85 // Sort matches by their score value 86 @usort($matches, function ($match1, $match2) { return $match2[0] - $match1[0]; }); 87 88 // If Highest rated method prophecy has a promise - execute it or return null instead 89 $returnValue = null; 90 $exception = null; 91 if ($promise = $matches[0][1]->getPromise()) { 92 try { 93 $returnValue = $promise->execute($arguments, $prophecy, $matches[0][1]); 94 } catch (\Exception $e) { 95 $exception = $e; 96 } 97 } 98 99 $this->recordedCalls[] = new Call( 100 $methodName, $arguments, $returnValue, $exception, $file, $line 101 ); 102 103 if (null !== $exception) { 104 throw $exception; 105 } 106 107 return $returnValue; 108 } 109 110 /** 111 * Searches for calls by method name & arguments wildcard. 112 * 113 * @param string $methodName 114 * @param ArgumentsWildcard $wildcard 115 * 116 * @return Call[] 117 */ 118 public function findCalls($methodName, ArgumentsWildcard $wildcard) 119 { 120 return array_values( 121 array_filter($this->recordedCalls, function (Call $call) use ($methodName, $wildcard) { 122 return $methodName === $call->getMethodName() 123 && 0 < $wildcard->scoreArguments($call->getArguments()) 124 ; 125 }) 126 ); 127 } 128 129 private function createUnexpectedCallException(ObjectProphecy $prophecy, $methodName, 130 array $arguments) 131 { 132 $classname = get_class($prophecy->reveal()); 133 $argstring = implode(', ', array_map(array($this->util, 'stringify'), $arguments)); 134 $expected = implode("\n", array_map(function (MethodProphecy $methodProphecy) { 135 return sprintf(' - %s(%s)', 136 $methodProphecy->getMethodName(), 137 $methodProphecy->getArgumentsWildcard() 138 ); 139 }, call_user_func_array('array_merge', $prophecy->getMethodProphecies()))); 140 141 return new UnexpectedCallException( 142 sprintf( 143 "Method call:\n". 144 " - %s(%s)\n". 145 "on %s was not expected, expected calls were:\n%s", 146 147 $methodName, $argstring, $classname, $expected 148 ), 149 $prophecy, $methodName, $arguments 150 ); 151 } 152 }