-
Notifications
You must be signed in to change notification settings - Fork 44
/
ServiceRouter.php
176 lines (155 loc) · 7.14 KB
/
ServiceRouter.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<?php
/**
* This file is part of amfPHP
*
* LICENSE
*
* This source file is subject to the license that is bundled
* with this package in the file license.txt.
*/
/**
* The Service Router class is responsible for executing the remote service method and returning it's value.
* based on the old 'Executive' of php 1.9. It looks for a service either explicitely defined in a
* ClassFindInfo object, or in a service folder.
*
* @package Amfphp_Core_Common
* @author Ariel Sommeria-klein
*/
class Amfphp_Core_Common_ServiceRouter {
/**
* filter called when the service object is created. Useful for authentication
* @param Object $serviceObject
* @param string $serviceName
* @param string $methodName
* @param array $parameters
*/
const FILTER_SERVICE_OBJECT = 'FILTER_SERVICE_OBJECT';
/**
* paths to folders containing services(relative or absolute)
* @var array of paths
*/
public $serviceFolders;
/**
*
* @var array of ClassFindInfo
*/
public $serviceNames2ClassFindInfo;
/**
* check parameters. This is useful for development, but should be disabled for production
* @var Boolean
*/
public $checkArgumentCount;
/**
* constructor
* @param array $serviceFolders folders containing service classes
* @param array $serviceNames2ClassFindInfo a dictionary of service classes represented in a ClassFindInfo.
* @param Boolean $checkArgumentCount
*/
public function __construct($serviceFolders, $serviceNames2ClassFindInfo, $checkArgumentCount = false) {
$this->serviceFolders = $serviceFolders;
$this->serviceNames2ClassFindInfo = $serviceNames2ClassFindInfo;
$this->checkArgumentCount = $checkArgumentCount;
}
/**
* get a service object by its name. Looks for a match in serviceNames2ClassFindInfo, then in the defined service folders.
* If none found, an exception is thrown
* this method is static so that it can be used also by the discovery service
* '__' are replaced by '/' to help the client generator support packages without messing with folders and the like
* the service object can either be in the global namespace or in the namespace suggested by the name.
* For example a call to Sub1/Sub2/NamespaceTestService will load the PHP file in Sub1/Sub2/NamespaceTestService,
* and return an instance of either NamespaceTestService or Sub1\Sub2\NamespaceTestService
*
* @param type $serviceName
* @param array $serviceFolders
* @param array $serviceNames2ClassFindInfo
* @return Object service object
*/
public static function getServiceObjectStatically($serviceName, array $serviceFolders, array $serviceNames2ClassFindInfo){
$serviceObject = null;
if (isset($serviceNames2ClassFindInfo[$serviceName])) {
$classFindInfo = $serviceNames2ClassFindInfo[$serviceName];
require_once $classFindInfo->absolutePath;
$serviceObject = new $classFindInfo->className();
} else {
$temp = str_replace('.', '/', $serviceName);
$serviceNameWithSlashes = str_replace('__', '/', $temp);
$serviceIncludePath = $serviceNameWithSlashes . '.php';
$exploded = explode('/', $serviceNameWithSlashes);
$className = $exploded[count($exploded) - 1];
//no class find info. try to look in the folders
foreach ($serviceFolders as $folder) {
$folderPath = NULL;
$rootNamespace = NULL;
if(is_array($folder)){
$rootNamespace = $folder[1];
$folderPath = $folder[0];
}else{
$folderPath = $folder;
}
$servicePath = $folderPath . $serviceIncludePath;
if (file_exists($servicePath)) {
require_once $servicePath;
if($rootNamespace == NULL){
$serviceObject = new $className();
}else{
$namespacedClassName = $rootNamespace . '\\' . str_replace('/', '\\', $serviceNameWithSlashes);
$serviceObject = new $namespacedClassName;
}
}
}
}
if (!$serviceObject) {
throw new Amfphp_Core_Exception("$serviceName service not found ");
}
return $serviceObject;
}
/**
* get service object
* @param String $serviceName
* @return Object service object
*/
public function getServiceObject($serviceName) {
return self::getServiceObjectStatically($serviceName, $this->serviceFolders, $this->serviceNames2ClassFindInfo);
}
/**
* loads and instanciates a service class matching $serviceName, then calls the function defined by $methodName using $parameters as parameters
* throws an exception if service not found.
* if the service exists but not the function, an exception is thrown by call_user_func_array. It is pretty explicit, so no further code was added
*
* @param string $serviceName
* @param string $methodName
* @param array $parameters
* @return mixed the result of the function call
*
*/
public function executeServiceCall($serviceName, $methodName, array $parameters) {
$unfilteredServiceObject = $this->getServiceObject($serviceName);
$serviceObject = Amfphp_Core_FilterManager::getInstance()->callFilters(self::FILTER_SERVICE_OBJECT, $unfilteredServiceObject, $serviceName, $methodName, $parameters);
$isStaticMethod = false;
if(method_exists($serviceObject, $methodName)){
//method exists, but isn't static
}else if (method_exists($serviceName, $methodName)) {
$isStaticMethod = true;
}else{
throw new Amfphp_Core_Exception("method $methodName not found on $serviceName object ");
}
if(substr($methodName, 0, 1) == '_'){
throw new Amfphp_Core_Exception("The method $methodName starts with a '_', and is therefore not accessible");
}
if($this->checkArgumentCount){
$method = new ReflectionMethod($serviceObject, $methodName);
$numberOfRequiredParameters = $method->getNumberOfRequiredParameters();
$numberOfParameters = $method->getNumberOfParameters();
$numberOfProvidedParameters = count($parameters);
if ($numberOfProvidedParameters < $numberOfRequiredParameters || $numberOfProvidedParameters > $numberOfParameters) {
throw new Amfphp_Core_Exception("Invalid number of parameters for method $methodName in service $serviceName : $numberOfRequiredParameters required, $numberOfParameters total, $numberOfProvidedParameters provided");
}
}
if($isStaticMethod){
return call_user_func_array(array($serviceName, $methodName), $parameters);
}else{
return call_user_func_array(array($serviceObject, $methodName), $parameters);
}
}
}
?>