Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
20 | class JsonRpcHandler extends AbstractRequestHandler implements BatchRequestHandlerInterface |
||
21 | { |
||
22 | /** |
||
23 | * Option key for a base path |
||
24 | */ |
||
25 | const KEY_BASE_PATH = 'basePath'; |
||
26 | |||
27 | /** |
||
28 | * Error constants from the JSON-RPC 2.0 spec. |
||
29 | */ |
||
30 | const ERR_PARSE_ERROR = -32700; |
||
31 | const ERR_INVALID_REQUEST = -32600; |
||
32 | const ERR_METHOD_NOT_FOUND = -32601; |
||
33 | const ERR_INVALID_PARAMS = -32602; |
||
34 | const ERR_INTERNAL_ERROR = -32603; |
||
35 | |||
36 | /** |
||
37 | * The path to the stdin stream. This can be set for testing. |
||
38 | * |
||
39 | * @var string |
||
40 | */ |
||
41 | private $stdin = 'php://input'; |
||
42 | |||
43 | /** |
||
44 | * An array of HttpRequest objects. |
||
45 | * |
||
46 | * @var array |
||
47 | */ |
||
48 | private $requests; |
||
49 | |||
50 | |||
51 | /** |
||
52 | * A flag indicating whether the request is a batch request. |
||
53 | * |
||
54 | * @var boolean |
||
55 | */ |
||
56 | private $batch; |
||
57 | |||
58 | /** |
||
59 | * The encoder instance to be used to encode responses. |
||
60 | * |
||
61 | * @var \Vectorface\SnappyRouter\Encoder\EncoderInterface|\Vectorface\SnappyRouter\Encoder\JsonEncoder |
||
62 | */ |
||
63 | private $encoder; |
||
64 | |||
65 | /** |
||
66 | * Returns true if the handler determines it should handle this request and false otherwise. |
||
67 | * |
||
68 | * @param string $path The URL path for the request. |
||
69 | * @param array $query The query parameters. |
||
70 | * @param array $post The post data. |
||
71 | * @param string $verb The HTTP verb used in the request. |
||
72 | * @return boolean Returns true if this handler will handle the request and false otherwise. |
||
73 | */ |
||
74 | 5 | public function isAppropriate($path, $query, $post, $verb) |
|
93 | |||
94 | /** |
||
95 | * Determine the service to load via the ServiceProvider based on path |
||
96 | * |
||
97 | * @param string $path The raw path (URI) used to determine the service. |
||
98 | * @return string The name of the service that we should attempt to load. |
||
99 | */ |
||
100 | 5 | private function getServiceFromPath($path) |
|
101 | { |
||
102 | /* Ensure the path is in a standard form, removing empty elements. */ |
||
103 | 5 | $path = implode('/', array_filter(array_map('trim', explode('/', $path)), 'strlen')); |
|
104 | |||
105 | /* If using the basePath option, strip the basePath. Otherwise, the path becomes the basename of the URI. */ |
||
106 | 5 | if (isset($this->options[self::KEY_BASE_PATH])) { |
|
107 | 1 | $basePathPosition = strpos($path, $this->options[self::KEY_BASE_PATH]); |
|
108 | 1 | View Code Duplication | if (false !== $basePathPosition) { |
|
|||
109 | 1 | $path = substr($path, $basePathPosition + strlen($this->options[self::KEY_BASE_PATH])); |
|
110 | } |
||
111 | |||
112 | 1 | return trim(dirname($path), "/") . '/' . basename($path, '.php'); /* For example, x/y/z/FooService */ |
|
113 | } else { |
||
114 | 4 | return basename($path, '.php'); /* For example: FooService, from /x/y/z/FooService.php */ |
|
115 | } |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Processes the payload POST data and sets up the array of requests. |
||
120 | * @param string $service The service being requested. |
||
121 | * @param string $verb The HTTP verb being used. |
||
122 | * @param array|object $post The raw POST data. |
||
123 | */ |
||
124 | 5 | private function processPayload($service, $verb, $post) |
|
125 | { |
||
126 | 5 | $this->batch = is_array($post); |
|
127 | 5 | if (false === $this->batch) { |
|
128 | 4 | $post = array($post); |
|
129 | } |
||
130 | 5 | $this->requests = array_map(function ($payload) use ($service, $verb) { |
|
131 | 4 | return new JsonRpcRequest($service, $payload, $verb); |
|
132 | 5 | }, $post); |
|
133 | 5 | } |
|
134 | |||
135 | /** |
||
136 | * Returns a request object extracted from the request details (path, query, etc). The method |
||
137 | * isAppropriate() must have returned true, otherwise this method should return null. |
||
138 | * @return HttpRequest Returns a Request object or null if this handler is not appropriate. |
||
139 | */ |
||
140 | 4 | public function getRequest() |
|
144 | |||
145 | /** |
||
146 | * Returns an array of batched requests. |
||
147 | * @return array An array of batched requests. |
||
148 | */ |
||
149 | 2 | public function getRequests() |
|
153 | |||
154 | /** |
||
155 | * Performs the actual routing. |
||
156 | * |
||
157 | * @return string Returns the result of the route. |
||
158 | */ |
||
159 | 3 | public function performRoute() |
|
198 | |||
199 | /** |
||
200 | * Invokes a method on a service class, based on the raw JSON-RPC request. |
||
201 | * |
||
202 | * @param mixed $service The service being invoked. |
||
203 | * @param Vectorface\SnappyRouter\Request\JsonRpcRequest $request The request |
||
204 | * to invoke. |
||
205 | * @return JsonRpcResponse A response based on the result of the procedure call. |
||
206 | */ |
||
207 | 2 | private function invokeMethod($service, JsonRpcRequest $request) |
|
249 | |||
250 | /** |
||
251 | * Returns the active response encoder. |
||
252 | * |
||
253 | * @return \Vectorface\SnappyRouter\Encoder\EncoderInterface Returns the response encoder. |
||
254 | */ |
||
255 | 2 | public function getEncoder() |
|
262 | |||
263 | /** |
||
264 | * Provides the handler with an opportunity to perform any last minute |
||
265 | * error handling logic. The returned value will be serialized by the |
||
266 | * handler's encoder. |
||
267 | * |
||
268 | * @param Exception $e The exception that was thrown. |
||
269 | * @return mixed Returns a serializable value that will be encoded and returned |
||
270 | * to the client. |
||
271 | */ |
||
272 | 1 | public function handleException(Exception $e) |
|
284 | } |
||
285 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.