*/
class VirtualRESTServiceClient {
/** @var MultiHttpClient */
- protected $http;
- /** @var Array Map of (prefix => VirtualRESTService) */
- protected $instances = [];
+ private $http;
+ /** @var array Map of (prefix => VirtualRESTService|array) */
+ private $instances = [];
const VALID_MOUNT_REGEX = '#^/[0-9a-z]+/([0-9a-z]+/)*$#';
/**
* Map a prefix to service handler
*
+ * If $instance is in array, it must have these keys:
+ * - class : string; fully qualified VirtualRESTService class name
+ * - config : array; map of parameters that is the first __construct() argument
+ *
* @param string $prefix Virtual path
- * @param VirtualRESTService $instance
+ * @param VirtualRESTService|array $instance Service or info to yield the service
*/
- public function mount( $prefix, VirtualRESTService $instance ) {
+ public function mount( $prefix, $instance ) {
if ( !preg_match( self::VALID_MOUNT_REGEX, $prefix ) ) {
throw new UnexpectedValueException( "Invalid service mount point '$prefix'." );
} elseif ( isset( $this->instances[$prefix] ) ) {
throw new UnexpectedValueException( "A service is already mounted on '$prefix'." );
}
+ if ( !( $instance instanceof VirtualRESTService ) ) {
+ if ( !isset( $instance['class'] ) || !isset( $instance['config'] ) ) {
+ throw new UnexpectedValueException( "Missing 'class' or 'config' ('$prefix')." );
+ }
+ }
$this->instances[$prefix] = $instance;
}
};
$matches = []; // matching prefixes (mount points)
- foreach ( $this->instances as $prefix => $service ) {
+ foreach ( $this->instances as $prefix => $unused ) {
if ( strpos( $path, $prefix ) === 0 ) {
$matches[] = $prefix;
}
usort( $matches, $cmpFunc );
// Return the most specific prefix and corresponding service
- return isset( $matches[0] )
- ? [ $matches[0], $this->instances[$matches[0]] ]
+ return $matches
+ ? [ $matches[0], $this->getInstance( $matches[0] ) ]
: [ null, null ];
}
// defer the original or to set a proxy response to the original.
$newReplaceReqsByService = [];
foreach ( $replaceReqsByService as $prefix => $servReqs ) {
- $service = $this->instances[$prefix];
+ $service = $this->getInstance( $prefix );
foreach ( $service->onRequests( $servReqs, $idFunc ) as $index => $req ) {
// Services use unique IDs for replacement requests
if ( isset( $servReqs[$index] ) || isset( $origPending[$index] ) ) {
$checkReqIndexesByPrefix[$prefix][$index] = 1;
}
}
- // Update index of requests to inspect for replacement
- $replaceReqsByService = $newReplaceReqsByService;
// Run the actual work HTTP requests
foreach ( $this->http->runMulti( $executeReqs ) as $index => $ranReq ) {
$doneReqs[$index] = $ranReq;
// forced by setting 'response' rather than actually be sent over the wire.
$newReplaceReqsByService = [];
foreach ( $checkReqIndexesByPrefix as $prefix => $servReqIndexes ) {
- $service = $this->instances[$prefix];
+ $service = $this->getInstance( $prefix );
// $doneReqs actually has the requests (with 'response' set)
$servReqs = array_intersect_key( $doneReqs, $servReqIndexes );
foreach ( $service->onResponses( $servReqs, $idFunc ) as $index => $req ) {
return $responses;
}
+
+ /**
+ * @param string $prefix
+ * @return VirtualRESTService
+ */
+ private function getInstance( $prefix ) {
+ if ( !isset( $this->instances[$prefix] ) ) {
+ throw new RuntimeException( "No service registered at prefix '{$prefix}'." );
+ }
+
+ if ( !( $this->instances[$prefix] instanceof VirtualRESTService ) ) {
+ $config = $this->instances[$prefix]['config'];
+ $class = $this->instances[$prefix]['class'];
+ $service = new $class( $config );
+ if ( !( $service instanceof VirtualRESTService ) ) {
+ throw new UnexpectedValueException( "Registered service has the wrong class." );
+ }
+ $this->instances[$prefix] = $service;
+ }
+
+ return $this->instances[$prefix];
+ }
}